ideapress 0.1.0__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 (192) hide show
  1. ideapress-0.1.0/.editorconfig +23 -0
  2. ideapress-0.1.0/.github/workflows/ci.yml +159 -0
  3. ideapress-0.1.0/.github/workflows/release.yml +30 -0
  4. ideapress-0.1.0/.gitignore +106 -0
  5. ideapress-0.1.0/.importlinter +40 -0
  6. ideapress-0.1.0/.pre-commit-config.yaml +22 -0
  7. ideapress-0.1.0/CHANGELOG.md +104 -0
  8. ideapress-0.1.0/CONTRIBUTING.md +50 -0
  9. ideapress-0.1.0/LICENSE +201 -0
  10. ideapress-0.1.0/PKG-INFO +103 -0
  11. ideapress-0.1.0/README.md +52 -0
  12. ideapress-0.1.0/SECURITY.md +39 -0
  13. ideapress-0.1.0/docs/README.md +9 -0
  14. ideapress-0.1.0/docs/apps/ideapress/api.md +102 -0
  15. ideapress-0.1.0/docs/apps/ideapress/data-model.md +212 -0
  16. ideapress-0.1.0/docs/apps/ideapress/development-plan.md +433 -0
  17. ideapress-0.1.0/docs/apps/ideapress/risks.md +108 -0
  18. ideapress-0.1.0/docs/apps/ideapress/spec.md +322 -0
  19. ideapress-0.1.0/docs/apps/ideapress/workflows.md +310 -0
  20. ideapress-0.1.0/pyproject.toml +146 -0
  21. ideapress-0.1.0/requirements/.gitkeep +1 -0
  22. ideapress-0.1.0/src/ideapress/__about__.py +1 -0
  23. ideapress-0.1.0/src/ideapress/__main__.py +8 -0
  24. ideapress-0.1.0/src/ideapress/bootstrap.py +58 -0
  25. ideapress-0.1.0/src/ideapress/cli/commands/backend.py +129 -0
  26. ideapress-0.1.0/src/ideapress/cli/commands/config.py +113 -0
  27. ideapress-0.1.0/src/ideapress/cli/commands/db.py +129 -0
  28. ideapress-0.1.0/src/ideapress/cli/commands/export.py +49 -0
  29. ideapress-0.1.0/src/ideapress/cli/commands/plan.py +106 -0
  30. ideapress-0.1.0/src/ideapress/cli/commands/project.py +164 -0
  31. ideapress-0.1.0/src/ideapress/cli/commands/prompts.py +92 -0
  32. ideapress-0.1.0/src/ideapress/cli/commands/stage.py +112 -0
  33. ideapress-0.1.0/src/ideapress/cli/commands/system.py +134 -0
  34. ideapress-0.1.0/src/ideapress/cli/commands/unit.py +162 -0
  35. ideapress-0.1.0/src/ideapress/cli/commands/workflow.py +69 -0
  36. ideapress-0.1.0/src/ideapress/cli/main.py +75 -0
  37. ideapress-0.1.0/src/ideapress/config.py +725 -0
  38. ideapress-0.1.0/src/ideapress/content_types/article/.gitkeep +0 -0
  39. ideapress-0.1.0/src/ideapress/content_types/registry.py +137 -0
  40. ideapress-0.1.0/src/ideapress/content_types/report/.gitkeep +0 -0
  41. ideapress-0.1.0/src/ideapress/domain/audit.py +138 -0
  42. ideapress-0.1.0/src/ideapress/domain/commit.py +233 -0
  43. ideapress-0.1.0/src/ideapress/domain/context_assembly.py +348 -0
  44. ideapress-0.1.0/src/ideapress/domain/critique.py +62 -0
  45. ideapress-0.1.0/src/ideapress/domain/exporters/html.py +165 -0
  46. ideapress-0.1.0/src/ideapress/domain/exporters/json.py +99 -0
  47. ideapress-0.1.0/src/ideapress/domain/exporters/markdown.py +92 -0
  48. ideapress-0.1.0/src/ideapress/domain/exporters/model.py +143 -0
  49. ideapress-0.1.0/src/ideapress/domain/inference.py +355 -0
  50. ideapress-0.1.0/src/ideapress/domain/plan.py +150 -0
  51. ideapress-0.1.0/src/ideapress/domain/project.py +132 -0
  52. ideapress-0.1.0/src/ideapress/domain/requirements.py +444 -0
  53. ideapress-0.1.0/src/ideapress/domain/revision_policy.py +149 -0
  54. ideapress-0.1.0/src/ideapress/domain/stage_state.py +110 -0
  55. ideapress-0.1.0/src/ideapress/domain/stages.py +189 -0
  56. ideapress-0.1.0/src/ideapress/domain/validation.py +158 -0
  57. ideapress-0.1.0/src/ideapress/domain/validators/.gitkeep +0 -0
  58. ideapress-0.1.0/src/ideapress/domain/validators/__init__.py +45 -0
  59. ideapress-0.1.0/src/ideapress/domain/validators/consistency.py +67 -0
  60. ideapress-0.1.0/src/ideapress/domain/validators/content.py +114 -0
  61. ideapress-0.1.0/src/ideapress/domain/validators/formatting.py +80 -0
  62. ideapress-0.1.0/src/ideapress/domain/validators/length.py +62 -0
  63. ideapress-0.1.0/src/ideapress/domain/validators/reference.py +124 -0
  64. ideapress-0.1.0/src/ideapress/domain/validators/safety.py +99 -0
  65. ideapress-0.1.0/src/ideapress/domain/validators/structural.py +156 -0
  66. ideapress-0.1.0/src/ideapress/errors.py +179 -0
  67. ideapress-0.1.0/src/ideapress/infrastructure/backends/_modelrack.py +402 -0
  68. ideapress-0.1.0/src/ideapress/infrastructure/backends/fake.py +248 -0
  69. ideapress-0.1.0/src/ideapress/infrastructure/backends/loadcoach.py +4 -0
  70. ideapress-0.1.0/src/ideapress/infrastructure/backends/ollama.py +207 -0
  71. ideapress-0.1.0/src/ideapress/infrastructure/backends/openai_compatible.py +175 -0
  72. ideapress-0.1.0/src/ideapress/infrastructure/db/.gitkeep +0 -0
  73. ideapress-0.1.0/src/ideapress/infrastructure/db/migrations/.gitkeep +0 -0
  74. ideapress-0.1.0/src/ideapress/infrastructure/db/migrations/env.py +34 -0
  75. ideapress-0.1.0/src/ideapress/infrastructure/db/migrations/script.py.mako +26 -0
  76. ideapress-0.1.0/src/ideapress/infrastructure/db/migrations/versions/0001_initial_schema.py +99 -0
  77. ideapress-0.1.0/src/ideapress/infrastructure/db/migrations/versions/0002_plan_tables.py +227 -0
  78. ideapress-0.1.0/src/ideapress/infrastructure/db/migrations/versions/0003_unit_versions.py +152 -0
  79. ideapress-0.1.0/src/ideapress/infrastructure/db/migrations/versions/0004_review_tables.py +87 -0
  80. ideapress-0.1.0/src/ideapress/infrastructure/db/migrations/versions/0005_stage_run_ownership.py +40 -0
  81. ideapress-0.1.0/src/ideapress/infrastructure/db/models.py +495 -0
  82. ideapress-0.1.0/src/ideapress/infrastructure/db/repositories/projects.py +162 -0
  83. ideapress-0.1.0/src/ideapress/observability/logging.py +157 -0
  84. ideapress-0.1.0/src/ideapress/prompts/.gitkeep +0 -0
  85. ideapress-0.1.0/src/ideapress/prompts/manifest.json +59 -0
  86. ideapress-0.1.0/src/ideapress/prompts/stages/audit_deep.review.v1.json +38 -0
  87. ideapress-0.1.0/src/ideapress/prompts/stages/audit_fast.review.v1.json +33 -0
  88. ideapress-0.1.0/src/ideapress/prompts/stages/critique.judge.v1.json +48 -0
  89. ideapress-0.1.0/src/ideapress/prompts/stages/draft.write.v1.json +28 -0
  90. ideapress-0.1.0/src/ideapress/prompts/stages/hello.v1.json +28 -0
  91. ideapress-0.1.0/src/ideapress/prompts/stages/outline.plan.v1.json +43 -0
  92. ideapress-0.1.0/src/ideapress/prompts/stages/project_review.consistency.v1.json +28 -0
  93. ideapress-0.1.0/src/ideapress/prompts/stages/repair.fix.v1.json +38 -0
  94. ideapress-0.1.0/src/ideapress/prompts/stages/requirements.compile.v1.json +34 -0
  95. ideapress-0.1.0/src/ideapress/prompts/stages/revise.improve.v1.json +38 -0
  96. ideapress-0.1.0/src/ideapress/services/backends.py +181 -0
  97. ideapress-0.1.0/src/ideapress/services/database.py +250 -0
  98. ideapress-0.1.0/src/ideapress/services/diagnostics.py +121 -0
  99. ideapress-0.1.0/src/ideapress/services/events.py +197 -0
  100. ideapress-0.1.0/src/ideapress/services/export.py +262 -0
  101. ideapress-0.1.0/src/ideapress/services/feedback.py +4 -0
  102. ideapress-0.1.0/src/ideapress/services/inference.py +310 -0
  103. ideapress-0.1.0/src/ideapress/services/plan.py +346 -0
  104. ideapress-0.1.0/src/ideapress/services/project_archive.py +4 -0
  105. ideapress-0.1.0/src/ideapress/services/project_review.py +143 -0
  106. ideapress-0.1.0/src/ideapress/services/projects.py +332 -0
  107. ideapress-0.1.0/src/ideapress/services/prompts.py +91 -0
  108. ideapress-0.1.0/src/ideapress/services/requirements.py +323 -0
  109. ideapress-0.1.0/src/ideapress/services/review.py +375 -0
  110. ideapress-0.1.0/src/ideapress/services/review_loop.py +410 -0
  111. ideapress-0.1.0/src/ideapress/services/runtime.py +224 -0
  112. ideapress-0.1.0/src/ideapress/services/stage_bodies.py +193 -0
  113. ideapress-0.1.0/src/ideapress/services/stage_registry.py +63 -0
  114. ideapress-0.1.0/src/ideapress/services/stage_reports.py +137 -0
  115. ideapress-0.1.0/src/ideapress/services/stages.py +457 -0
  116. ideapress-0.1.0/src/ideapress/services/unit_loop.py +426 -0
  117. ideapress-0.1.0/src/ideapress/services/unit_reports.py +192 -0
  118. ideapress-0.1.0/src/ideapress/services/units.py +297 -0
  119. ideapress-0.1.0/src/ideapress/web/app.py +290 -0
  120. ideapress-0.1.0/src/ideapress/web/csrf.py +50 -0
  121. ideapress-0.1.0/src/ideapress/web/limits.py +89 -0
  122. ideapress-0.1.0/src/ideapress/web/rendering.py +69 -0
  123. ideapress-0.1.0/src/ideapress/web/routes/backends.py +57 -0
  124. ideapress-0.1.0/src/ideapress/web/routes/export.py +59 -0
  125. ideapress-0.1.0/src/ideapress/web/routes/plan.py +32 -0
  126. ideapress-0.1.0/src/ideapress/web/routes/projects.py +199 -0
  127. ideapress-0.1.0/src/ideapress/web/routes/settings.py +151 -0
  128. ideapress-0.1.0/src/ideapress/web/routes/stages.py +178 -0
  129. ideapress-0.1.0/src/ideapress/web/routes/system.py +106 -0
  130. ideapress-0.1.0/src/ideapress/web/routes/units.py +122 -0
  131. ideapress-0.1.0/src/ideapress/web/routes/workspace.py +4 -0
  132. ideapress-0.1.0/src/ideapress/web/static/js/diff.js +1 -0
  133. ideapress-0.1.0/src/ideapress/web/static/js/workspace.js +1 -0
  134. ideapress-0.1.0/src/ideapress/web/templates/.gitkeep +0 -0
  135. ideapress-0.1.0/src/ideapress/web/templates/backends/index.html +38 -0
  136. ideapress-0.1.0/src/ideapress/web/templates/base.html +6 -0
  137. ideapress-0.1.0/src/ideapress/web/templates/error.html +14 -0
  138. ideapress-0.1.0/src/ideapress/web/templates/plan/index.html +63 -0
  139. ideapress-0.1.0/src/ideapress/web/templates/projects/detail.html +23 -0
  140. ideapress-0.1.0/src/ideapress/web/templates/projects/index.html +42 -0
  141. ideapress-0.1.0/src/ideapress/web/templates/system/index.html +20 -0
  142. ideapress-0.1.0/src/ideapress/web/templates/units/detail.html +127 -0
  143. ideapress-0.1.0/tests/accessibility/test_ui_checklist.py +4 -0
  144. ideapress-0.1.0/tests/conftest.py +59 -0
  145. ideapress-0.1.0/tests/contract/test_backend_conformance.py +247 -0
  146. ideapress-0.1.0/tests/contract/test_envelope_conformance.py +276 -0
  147. ideapress-0.1.0/tests/contract/test_loadcoach_backend.py +4 -0
  148. ideapress-0.1.0/tests/e2e/test_backends_surface.py +151 -0
  149. ideapress-0.1.0/tests/e2e/test_cli_skeleton.py +125 -0
  150. ideapress-0.1.0/tests/e2e/test_export_dialog.py +4 -0
  151. ideapress-0.1.0/tests/e2e/test_full_project_journey.py +4 -0
  152. ideapress-0.1.0/tests/e2e/test_plan_cli.py +256 -0
  153. ideapress-0.1.0/tests/e2e/test_plan_editing.py +4 -0
  154. ideapress-0.1.0/tests/e2e/test_project_crud.py +197 -0
  155. ideapress-0.1.0/tests/e2e/test_stage_stream.py +334 -0
  156. ideapress-0.1.0/tests/e2e/test_system.py +159 -0
  157. ideapress-0.1.0/tests/e2e/test_workspace.py +4 -0
  158. ideapress-0.1.0/tests/integration/test_atomic_commit.py +299 -0
  159. ideapress-0.1.0/tests/integration/test_backend_parity.py +277 -0
  160. ideapress-0.1.0/tests/integration/test_draft_to_commit.py +335 -0
  161. ideapress-0.1.0/tests/integration/test_export.py +352 -0
  162. ideapress-0.1.0/tests/integration/test_loadcoach_degradation.py +4 -0
  163. ideapress-0.1.0/tests/integration/test_migrations.py +105 -0
  164. ideapress-0.1.0/tests/integration/test_plan_stage.py +521 -0
  165. ideapress-0.1.0/tests/integration/test_project_service.py +159 -0
  166. ideapress-0.1.0/tests/integration/test_review_loop.py +374 -0
  167. ideapress-0.1.0/tests/live/test_backend_live.py +161 -0
  168. ideapress-0.1.0/tests/live/test_core_loop_live.py +109 -0
  169. ideapress-0.1.0/tests/live/test_loadcoach_live.py +4 -0
  170. ideapress-0.1.0/tests/performance/.gitkeep +0 -0
  171. ideapress-0.1.0/tests/security/.gitkeep +0 -0
  172. ideapress-0.1.0/tests/unit/test_ci_workflow.py +114 -0
  173. ideapress-0.1.0/tests/unit/test_commit_gate.py +191 -0
  174. ideapress-0.1.0/tests/unit/test_config.py +209 -0
  175. ideapress-0.1.0/tests/unit/test_content_types.py +117 -0
  176. ideapress-0.1.0/tests/unit/test_context_budget.py +274 -0
  177. ideapress-0.1.0/tests/unit/test_diminishing_returns.py +4 -0
  178. ideapress-0.1.0/tests/unit/test_escalation.py +4 -0
  179. ideapress-0.1.0/tests/unit/test_exporters.py +308 -0
  180. ideapress-0.1.0/tests/unit/test_import_boundaries.py +142 -0
  181. ideapress-0.1.0/tests/unit/test_logging.py +85 -0
  182. ideapress-0.1.0/tests/unit/test_plan_gates.py +121 -0
  183. ideapress-0.1.0/tests/unit/test_project_domain.py +80 -0
  184. ideapress-0.1.0/tests/unit/test_prompt_pack.py +126 -0
  185. ideapress-0.1.0/tests/unit/test_repair_loop.py +4 -0
  186. ideapress-0.1.0/tests/unit/test_requirement_checks.py +221 -0
  187. ideapress-0.1.0/tests/unit/test_requirement_compilation.py +362 -0
  188. ideapress-0.1.0/tests/unit/test_revision_stop.py +207 -0
  189. ideapress-0.1.0/tests/unit/test_single_model_invariant.py +305 -0
  190. ideapress-0.1.0/tests/unit/test_stage_state.py +106 -0
  191. ideapress-0.1.0/tests/unit/test_stage_vocabulary.py +138 -0
  192. ideapress-0.1.0/tests/unit/test_validators.py +407 -0
@@ -0,0 +1,23 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [*.py]
12
+ indent_size = 4
13
+ max_line_length = 100
14
+
15
+ [*.{toml,yml,yaml,json}]
16
+ indent_size = 2
17
+
18
+ [*.md]
19
+ trim_trailing_whitespace = false
20
+ max_line_length = off
21
+
22
+ [Makefile]
23
+ indent_style = tab
@@ -0,0 +1,159 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ format:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with: { python-version: "3.12" }
15
+ - run: pip install ruff
16
+ - run: ruff format --check .
17
+
18
+ lint:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: actions/setup-python@v5
23
+ with: { python-version: "3.12" }
24
+ - run: pip install ruff
25
+ - run: ruff check .
26
+
27
+ types:
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: actions/setup-python@v5
32
+ with: { python-version: "3.12" }
33
+ - run: pip install -e ".[dev]"
34
+ - run: mypy src tests
35
+
36
+ boundaries:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ - uses: actions/setup-python@v5
41
+ with: { python-version: "3.12" }
42
+ - run: pip install -e ".[dev]"
43
+ - run: lint-imports
44
+
45
+ tests:
46
+ runs-on: ubuntu-latest
47
+ strategy:
48
+ matrix:
49
+ python-version: ["3.12", "3.13"]
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+ - uses: actions/setup-python@v5
53
+ with: { python-version: "${{ matrix.python-version }}" }
54
+ - run: pip install -e ".[dev]"
55
+ - run: pytest -m "not live and not performance" --cov --cov-report=xml
56
+
57
+ tests-314-early-warning:
58
+ runs-on: ubuntu-latest
59
+ continue-on-error: true
60
+ steps:
61
+ - uses: actions/checkout@v4
62
+ - uses: actions/setup-python@v5
63
+ with: { python-version: "3.14" }
64
+ - run: pip install -e ".[dev]"
65
+ - run: pytest -m "not live and not performance"
66
+
67
+ db-matrix:
68
+ name: tests (PostgreSQL)
69
+ runs-on: ubuntu-latest
70
+ services:
71
+ postgres:
72
+ image: postgres:16
73
+ # Credentials and database name match `weightsdb.testing`'s documented default URL, so the
74
+ # service this job starts is the one the package looks for. The scaffold named a
75
+ # `postgres`/`postgres` server nothing ever connected to, and passed it as
76
+ # `DATABASE_URL` — a variable `temporary_postgres` does not read — in the bare
77
+ # `postgresql://` form, which resolves to the psycopg2 driver this project does not
78
+ # install. LoadCoach fixed the same three defects in its own job.
79
+ env:
80
+ POSTGRES_USER: weightsdb
81
+ POSTGRES_PASSWORD: weightsdb
82
+ POSTGRES_DB: weightsdb_test
83
+ ports: ["5432:5432"]
84
+ options: >-
85
+ --health-cmd "pg_isready -U weightsdb -d weightsdb_test" --health-interval 5s --health-timeout 5s --health-retries 10
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+ - uses: actions/setup-python@v5
89
+ with: { python-version: "3.12" }
90
+ - run: pip install -e ".[dev,postgres]"
91
+ # `-m integration` selects on a marker this repo never declares or applies, so it collected
92
+ # zero tests and exited 5 — the job would be red on every commit while appearing to test
93
+ # PostgreSQL (M4 handoff HR2, defect 2, which is why both siblings select by path).
94
+ - run: pytest -m "not live and not performance" tests/integration
95
+ env:
96
+ # A silently skipped dialect is an untested dialect: this turns the skip into a failure.
97
+ WEIGHTSDB_REQUIRE_POSTGRES: "1"
98
+ WEIGHTSDB_POSTGRES_URL: postgresql+psycopg://weightsdb:weightsdb@localhost:5432/weightsdb_test
99
+
100
+ coverage:
101
+ needs: [tests]
102
+ runs-on: ubuntu-latest
103
+ steps:
104
+ - uses: actions/checkout@v4
105
+ - uses: actions/setup-python@v5
106
+ with: { python-version: "3.12" }
107
+ - run: pip install -e ".[dev]"
108
+ - run: pytest -m "not live and not performance" --cov --cov-report=term-missing --cov-fail-under=85
109
+
110
+ contracts:
111
+ runs-on: ubuntu-latest
112
+ steps:
113
+ - uses: actions/checkout@v4
114
+ - uses: actions/setup-python@v5
115
+ with: { python-version: "3.12" }
116
+ - run: pip install -e ".[dev]"
117
+ - run: pytest -m contract
118
+
119
+ security:
120
+ runs-on: ubuntu-latest
121
+ steps:
122
+ - uses: actions/checkout@v4
123
+ # gitleaks scans *history*, and `actions/checkout` fetches a single commit by default.
124
+ # For a push it is handed `<first-pushed>^..<last-pushed>`, so the parent of the first
125
+ # pushed commit has to be in the object store; in a depth-1 clone it is not, and git
126
+ # answers "unknown revision", which the action reports as exit code 1. It fails the same
127
+ # way whether or not a secret exists, so a green run would not have meant anything either.
128
+ with: { fetch-depth: 0 }
129
+ - uses: actions/setup-python@v5
130
+ with: { python-version: "3.12" }
131
+ - run: pip install pip-audit
132
+ - run: pip-audit
133
+ - uses: gitleaks/gitleaks-action@v2
134
+ env:
135
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
136
+
137
+ build:
138
+ runs-on: ubuntu-latest
139
+ steps:
140
+ - uses: actions/checkout@v4
141
+ - uses: actions/setup-python@v5
142
+ with: { python-version: "3.12" }
143
+ - run: pip install build twine
144
+ - run: python -m build
145
+ - run: twine check dist/*
146
+ - uses: actions/upload-artifact@v4
147
+ with: { name: dist, path: dist/ }
148
+
149
+ install-check:
150
+ needs: [build]
151
+ runs-on: ubuntu-latest
152
+ steps:
153
+ - uses: actions/checkout@v4
154
+ - uses: actions/setup-python@v5
155
+ with: { python-version: "3.12" }
156
+ - uses: actions/download-artifact@v4
157
+ with: { name: dist, path: dist/ }
158
+ - run: pip install dist/*.whl
159
+ - run: python -c "import ideapress"
@@ -0,0 +1,30 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*.*.*"]
6
+
7
+ permissions:
8
+ id-token: write # required for PyPI Trusted Publishing
9
+ contents: write # required to create the GitHub release
10
+
11
+ jobs:
12
+ release:
13
+ runs-on: ubuntu-latest
14
+ environment: pypi
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with: { python-version: "3.12" }
19
+ - run: pip install build twine
20
+ - run: python -m build
21
+ - run: twine check dist/*
22
+ - run: pip install "dist/$(ls dist | grep .whl)[dev]"
23
+ - run: pytest -m "not live and not performance"
24
+ - name: Publish to PyPI
25
+ uses: pypa/gh-action-pypi-publish@release/v1
26
+ - name: Create GitHub release
27
+ uses: softprops/action-gh-release@v2
28
+ with:
29
+ generate_release_notes: true
30
+ files: dist/*
@@ -0,0 +1,106 @@
1
+ # ---- Python ----
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+ MANIFEST
23
+
24
+ # ---- Packaging / build backends ----
25
+ pip-wheel-metadata/
26
+ share/python-wheels/
27
+
28
+ # ---- Testing / coverage ----
29
+ .pytest_cache/
30
+ .cache
31
+ .coverage
32
+ .coverage.*
33
+ coverage.xml
34
+ *.cover
35
+ *.py,cover
36
+ htmlcov/
37
+ nosetests.xml
38
+ .hypothesis/
39
+
40
+ # ---- Type checking / linting ----
41
+ .mypy_cache/
42
+ .dmypy.json
43
+ dmypy.json
44
+ .ruff_cache/
45
+ .pytype/
46
+
47
+ # ---- Virtual environments ----
48
+ .venv/
49
+ venv/
50
+ ENV/
51
+ env/
52
+ env.bak/
53
+ venv.bak/
54
+ .python-version
55
+
56
+ # ---- Distribution / dependency locking ----
57
+ # requirements/*.lock is deliberately NOT ignored. The lock files are committed
58
+ # inputs: CI and release jobs install from them with --require-hashes (Packaging
59
+ # and Release Standards §4, Security Standards §11), so an ignored lock file
60
+ # means a checkout that cannot build.
61
+
62
+ # ---- Editors / OS ----
63
+ .vscode/
64
+ .idea/
65
+ *.swp
66
+ *.swo
67
+ .DS_Store
68
+ Thumbs.db
69
+
70
+ # ---- Suite runtime state (this component's local data) ----
71
+ # The application writes to XDG paths at runtime (~/.config, ~/.local/share,
72
+ # ~/.local/state per Master Architecture §1.2), never inside the repository.
73
+ # These entries only guard against a developer pointing XDG_* at the repo
74
+ # during local testing.
75
+ .local/
76
+ .config/
77
+ *.sqlite3
78
+ *.sqlite3-journal
79
+ *.sqlite3-wal
80
+ *.sqlite3-shm
81
+ /data/
82
+ /logs/
83
+ /backups/
84
+ /artifacts/
85
+ /exports/
86
+
87
+ # ---- Secrets ----
88
+ # Per Security Standards §8: secrets are never committed. Config files may
89
+ # only name where a secret comes from (*_env / *_file), never the value.
90
+ .env
91
+ .env.*
92
+ *.key
93
+ *.pem
94
+ secrets.toml
95
+
96
+ # ---- Node-free JS assets (MirrorWall consumers may still use a local tool) ----
97
+ node_modules/
98
+
99
+ # ---- Build artifacts from docs generation ----
100
+ docs/api/openapi-v1.json.tmp
101
+
102
+ # ---- Milestone evidence (transcripts, exports and hashes from a build run) ----
103
+ # M7's exit condition is a demonstration, and the artefacts it produces — briefs, generated
104
+ # documents, three export formats, hash comparisons, resident-model polls — are evidence for a
105
+ # handoff, not source. They stay on disk for the reader of that handoff and out of the history.
106
+ .m7-evidence/
@@ -0,0 +1,40 @@
1
+ [importlinter]
2
+ root_package = ideapress
3
+ include_external_packages = True
4
+
5
+ [importlinter:contract:layers]
6
+ name = IdeaPress internal layering
7
+ type = layers
8
+ layers =
9
+ web
10
+ cli
11
+ services
12
+ domain
13
+ containers = ideapress
14
+
15
+ [importlinter:contract:web-cli-independence]
16
+ name = Web and CLI never import each other
17
+ type = independence
18
+ modules =
19
+ ideapress.web
20
+ ideapress.cli
21
+
22
+ [importlinter:contract:domain-purity]
23
+ name = Domain imports no frameworks
24
+ type = forbidden
25
+ source_modules = ideapress.domain
26
+ forbidden_modules =
27
+ fastapi
28
+ starlette
29
+ sqlalchemy
30
+ typer
31
+ httpx
32
+ jinja2
33
+
34
+ [importlinter:contract:no-other-applications]
35
+ name = IdeaPress must not import other applications
36
+ type = forbidden
37
+ source_modules = ideapress
38
+ forbidden_modules =
39
+ freeweight
40
+ loadcoach
@@ -0,0 +1,22 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.6.9
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: https://github.com/pre-commit/pre-commit-hooks
9
+ rev: v4.6.0
10
+ hooks:
11
+ - id: trailing-whitespace
12
+ - id: end-of-file-fixer
13
+ - id: check-toml
14
+ - id: check-json
15
+ - id: check-added-large-files
16
+ - id: check-merge-conflict
17
+ - id: mixed-line-ending
18
+ args: [--fix=lf]
19
+ - repo: https://github.com/gitleaks/gitleaks
20
+ rev: v8.18.4
21
+ hooks:
22
+ - id: gitleaks
@@ -0,0 +1,104 @@
1
+ # Changelog
2
+
3
+ All notable changes to `ideapress` are documented here.
4
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
5
+ [Semantic Versioning](https://semver.org/), pre-1.0 per
6
+ packaging and release standards §3.
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+ - `GET`/`PUT /settings`, `GET /workflows/{id}`, `POST /projects/{id}/units/{unit_id}/revise`, and
12
+ the `workflow` and `prompts` command groups — the four endpoints and two groups the specification
13
+ lists that the phases had not yet built.
14
+ - Exporters for Markdown, HTML and JSON, byte-identical for the same committed project across
15
+ repeats, locales, timezones and hash seeds. The HTML is a single self-contained file with no
16
+ external reference of any kind, so it opens with no network.
17
+ - Export format versioning, recorded on every export and embedded in every rendered document.
18
+ - `GET`/`POST /projects/{id}/export`, `GET /export/formats`, and `ideapress export run|formats`.
19
+ - The `project_review` stage: cross-unit consistency findings, advisory by design.
20
+ - The open content-type registry, with `article` and `report` shipped.
21
+ - Review: `audit_fast`, `audit_deep` (escalation only, once per unit per round), `critique` with
22
+ "leave it alone" as a first-class verdict, and `revise` bounded by the round limit or by
23
+ diminishing returns computed from deterministic finding counts. Which stop applied is recorded.
24
+ - A revision that increases validation failures is rejected and the previous version kept.
25
+ - Migration `0004`: `audit_findings`, `critiques`. The findings, their severity and evidence, and
26
+ what changed between rounds, on the unit page.
27
+ - The core loop: draft, validate, repair (bounded, then pause the unit), coverage and an atomic
28
+ commit, with complete provenance on every committed version.
29
+ - Migration `0003`: `unit_versions`, `validations`, `coverage`, `exports`.
30
+ - The unit page and `ideapress unit list|show|history`, showing content, coverage, validation and
31
+ the attempts that produced it.
32
+ - Deterministic validation: all seven families from workflows §4 — structural, length, format,
33
+ content constraints, reference integrity, consistency and safety — with failures classed blocking
34
+ or advisory, and no model involved anywhere.
35
+ - Context assembly to a token budget, with the reduction order as data. Requirements and the unit
36
+ specification are never dropped; when they alone exceed the budget the stage fails carrying both
37
+ the required figure and the budget.
38
+ - The stage runner: a background thread per stage, the unit state machine as a transition table,
39
+ persisted gap-free stage events, and SSE that replays from `Last-Event-ID` after a disconnect.
40
+ - `POST /projects/{id}/plan`, `POST /projects/{id}/stages/{stage}/run`, the task and stream
41
+ endpoints, `GET /workflows`, and the plan page showing each requirement beside its quotation.
42
+ - `ideapress plan build|show` and `ideapress stage run|list|status|cancel`.
43
+ - Migration `0002`: `requirements`, `units`, `stage_runs`, `attempts`, `stage_events`.
44
+ - Requirement compilation: every requirement carries a verbatim quotation from the author material,
45
+ and one that cannot be quoted is refused and shown as refused. Check kinds are a closed set of
46
+ literal-string and numeric comparisons; there is deliberately no pattern check.
47
+ - The plan gate: every blocking requirement must be assigned to at least one unit, and an empty
48
+ requirement list or an empty plan does not satisfy it.
49
+ - The inference port (`InferenceBackend`, `StageRequest`, `StageResult`, `StageEvent`,
50
+ `BackendHealth`) and three adapters: Ollama over ModelRack, a deterministic offline fake, and an
51
+ OpenAI-compatible one. Switching between them is configuration.
52
+ - One generation runs at a time, through one function, and the resident model is unloaded before a
53
+ different one loads (ADR-0038).
54
+ - The prompt pack on `setspec.prompts`: versioned JSON records with a hashed manifest.
55
+ - `GET /backends`, `POST /backends/test`, a backend page that states where content goes, and
56
+ `ideapress backend list|test|switch`.
57
+ - Projects: create, list, open, update, archive, and delete with a preview of exactly what will be
58
+ removed. Slugs are derived from the title and never taken from input, and a project's artifact
59
+ directory is created private and containment-checked.
60
+ - Migration `0001` on WeightsDB's runner: `projects`, `sources`, `settings`, `api_tokens`, verified
61
+ against both SQLite and PostgreSQL 16 including the Alembic-to-models parity check.
62
+ - `ideapress project create|list|show|archive|delete` and `ideapress db upgrade|status|backup|restore`.
63
+ - Project list and detail pages, with the shared CSRF token on every form.
64
+ - Application skeleton on the shared packages: typed settings with the documented precedence and
65
+ refusals, structured logging with the suite's correlation fields, `/health`, `/version`,
66
+ `/system/status`, the system page, and the `serve`/`health`/`doctor`/`version`/`config` commands.
67
+ - `[execution]` configuration: `max_concurrent_stages` (only 1 is accepted; a higher value is
68
+ refused at startup) and `unload_before_model_switch`.
69
+ - A startup check that `[models.stages]`, `StageId` and workflows §2 name the same stages, and
70
+ refuses a binding for a stage that does not exist or a model-using stage with none.
71
+
72
+ ### Fixed
73
+ - An export's recorded `sha256` is now the file's own digest, so `sha256sum` on the exported file
74
+ reproduces it.
75
+ - A second process opening the database no longer marks a running stage as interrupted. Migration
76
+ `0005` records which process owns a stage run, and only a run whose owner is gone is marked.
77
+ - `/api/v1/docs` and `/api/v1/openapi.json` work: response annotations imported only under
78
+ `TYPE_CHECKING` left forward references FastAPI could not resolve, so building the schema raised.
79
+ - The CI workflow parses again: an edit had left a duplicate `env:` key on one step, which GitHub
80
+ refuses and PyYAML accepts, so the whole workflow was invalid and no job ran. A test now loads it
81
+ with a loader that refuses duplicate keys the way GitHub does.
82
+ - The PostgreSQL CI job now names the server `weightsdb.testing` looks for, passes
83
+ `WEIGHTSDB_POSTGRES_URL` rather than `DATABASE_URL`, and uses the `+psycopg` driver this project
84
+ installs; it previously could not connect at all.
85
+ - `pytest` now collects under the bare console script as well as `python -m pytest`
86
+ (`pythonpath = ["."]`), which is the invocation CI runs.
87
+ - Coverage measures the importable `ideapress` package rather than the `src/ideapress` path, so a
88
+ non-editable install reports real coverage instead of 0 %.
89
+ - The PostgreSQL CI job selects tests by path; it previously selected a marker this repository never
90
+ declares, collecting nothing.
91
+ - `ruff` no longer formats `docs/`, which is a byte-identical mirror of the suite documentation.
92
+ - Restored the six mirrored `docs/apps/ideapress/` documents; three were missing and three had been
93
+ edited downstream.
94
+
95
+ ### Changed
96
+ - `loadcoach` moved out of the `dev` extra into a `loadcoach-contract` extra, so the default
97
+ development and CI environment has no other application installed.
98
+
99
+ - Widened the `sweatmeter` pin to `>=0.4,<0.5`. SweatMeter's first published release is `0.4.0`
100
+ (`0.3.0` completed its development plan but never reached the index), and it adds the in-process
101
+ NVML GPU backend, selected automatically wherever the optional `pynvml` extra is installed.
102
+
103
+ ### Added
104
+ - Repository scaffold generated from the suite's development plan (no functional code yet).
@@ -0,0 +1,50 @@
1
+ # Contributing to IdeaPress
2
+
3
+ This repository is one component of the Local AI Suite. Before changing anything, read
4
+ `docs/apps/ideapress/spec.md` and the current
5
+ phase in `development-plan.md` — both are in this repository's `docs/` folder, copied from the suite's
6
+ central documentation set so this repository can be worked on independently.
7
+
8
+ ## Development setup
9
+
10
+ ```bash
11
+ python -m venv .venv
12
+ source .venv/bin/activate
13
+ pip install -e ".[dev]"
14
+ pre-commit install
15
+ ```
16
+
17
+ ## Required reading, in order
18
+
19
+ 1. This component's spec — purpose, scope, non-goals, contracts.
20
+ 2. `development-plan.md` in the same folder — the phase you are implementing, its acceptance criteria and its tests.
21
+
22
+ ## Rules that apply to every change here
23
+
24
+ * Follow the architecture's dependency direction.
25
+ This repository's `.importlinter` enforces it in CI; do not weaken that file to make an import work.
26
+ * No business logic in a route handler or CLI command body — both call one service method and render
27
+ .
28
+ * An unavailable measurement is `Unsupported`, never zero, never `None` used as a substitute
29
+ .
30
+ * Prompts are versioned JSON records, not Python string literals.
31
+ * Every phase's acceptance criteria in `development-plan.md` must be demonstrable, not merely
32
+ test-covered — the plan states what to run and what a person should see.
33
+
34
+ ## Before opening a pull request
35
+
36
+ ```bash
37
+ ruff format --check .
38
+ ruff check .
39
+ mypy src tests
40
+ lint-imports
41
+ pytest -m "not live and not performance"
42
+ ```
43
+
44
+ All of the above run in CI (`.github/workflows/ci.yml`); a red CI run blocks merge.
45
+
46
+ ## Commit style
47
+
48
+ Conventional Commits (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`, `perf:`, `build:`,
49
+ `ci:`), with `!` or a `BREAKING CHANGE:` footer for breaking changes. Update `CHANGELOG.md` under
50
+ `## [Unreleased]` for any user-visible change.