controlm-chain-admin 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 (268) hide show
  1. controlm_chain_admin-0.1.0/.claude/ATTRIBUTION.md +41 -0
  2. controlm_chain_admin-0.1.0/.claude/skills/bootstrap/SKILL.md +116 -0
  3. controlm_chain_admin-0.1.0/.claude/skills/fastapi-api/SKILL.md +70 -0
  4. controlm_chain_admin-0.1.0/.claude/skills/oss-repo-standards/SKILL.md +68 -0
  5. controlm_chain_admin-0.1.0/.claude/skills/oss-repo-standards/check_repo.sh +45 -0
  6. controlm_chain_admin-0.1.0/.claude/skills/python-core-tdd/SKILL.md +82 -0
  7. controlm_chain_admin-0.1.0/.claude/skills/react-frontend/SKILL.md +71 -0
  8. controlm_chain_admin-0.1.0/.claude/skills/verify/SKILL.md +64 -0
  9. controlm_chain_admin-0.1.0/.claude/skills/verify/verify.sh +73 -0
  10. controlm_chain_admin-0.1.0/.editorconfig +18 -0
  11. controlm_chain_admin-0.1.0/.github/FUNDING.yml +1 -0
  12. controlm_chain_admin-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +25 -0
  13. controlm_chain_admin-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  14. controlm_chain_admin-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +23 -0
  15. controlm_chain_admin-0.1.0/.github/workflows/ci.yml +91 -0
  16. controlm_chain_admin-0.1.0/.github/workflows/release.yml +47 -0
  17. controlm_chain_admin-0.1.0/.gitignore +37 -0
  18. controlm_chain_admin-0.1.0/.pre-commit-config.yaml +18 -0
  19. controlm_chain_admin-0.1.0/BACKLOG.md +221 -0
  20. controlm_chain_admin-0.1.0/CHANGELOG.md +186 -0
  21. controlm_chain_admin-0.1.0/CLAUDE.md +44 -0
  22. controlm_chain_admin-0.1.0/CODE_OF_CONDUCT.md +31 -0
  23. controlm_chain_admin-0.1.0/CONTRIBUTING.md +63 -0
  24. controlm_chain_admin-0.1.0/DESIGN.md +731 -0
  25. controlm_chain_admin-0.1.0/LICENSE +21 -0
  26. controlm_chain_admin-0.1.0/PKG-INFO +186 -0
  27. controlm_chain_admin-0.1.0/README.md +140 -0
  28. controlm_chain_admin-0.1.0/SECURITY.md +25 -0
  29. controlm_chain_admin-0.1.0/pyproject.toml +111 -0
  30. controlm_chain_admin-0.1.0/src/controlm_chain_admin/__init__.py +3 -0
  31. controlm_chain_admin-0.1.0/src/controlm_chain_admin/__main__.py +10 -0
  32. controlm_chain_admin-0.1.0/src/controlm_chain_admin/cli.py +1239 -0
  33. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/__init__.py +5 -0
  34. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/attribute_groups.py +61 -0
  35. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/commit.py +243 -0
  36. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/compare.py +806 -0
  37. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/constants.py +371 -0
  38. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/errors.py +131 -0
  39. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/fixes.py +433 -0
  40. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/graph.py +157 -0
  41. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/guide.py +76 -0
  42. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/history.py +335 -0
  43. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/inspect.py +105 -0
  44. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/intake.py +1148 -0
  45. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/jsonmodel.py +253 -0
  46. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/letter.py +169 -0
  47. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/links.py +299 -0
  48. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/membership.py +36 -0
  49. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/model.py +67 -0
  50. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/ops.py +656 -0
  51. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/overrides.py +113 -0
  52. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/package.py +318 -0
  53. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/refactor.py +1301 -0
  54. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/relations.py +194 -0
  55. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/repo.py +339 -0
  56. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/selection.py +189 -0
  57. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/take.py +567 -0
  58. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/validate.py +454 -0
  59. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/workspace.py +592 -0
  60. controlm_chain_admin-0.1.0/src/controlm_chain_admin/core/xmlio.py +151 -0
  61. controlm_chain_admin-0.1.0/src/controlm_chain_admin/py.typed +0 -0
  62. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/__init__.py +1 -0
  63. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/app.py +136 -0
  64. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/deps.py +27 -0
  65. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/errors.py +82 -0
  66. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/__init__.py +1 -0
  67. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/changes.py +55 -0
  68. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/environments.py +26 -0
  69. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/folders.py +100 -0
  70. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/history.py +136 -0
  71. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/intake.py +31 -0
  72. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/jobs.py +63 -0
  73. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/package.py +77 -0
  74. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/repo.py +27 -0
  75. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/table.py +17 -0
  76. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/validate.py +36 -0
  77. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/routers/workspace.py +127 -0
  78. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/schemas.py +525 -0
  79. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/serve.py +23 -0
  80. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/settings.py +30 -0
  81. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/static/assets/graph-CA0VXlpl.js +31 -0
  82. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/static/assets/index-BA0sPihz.css +1 -0
  83. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/static/assets/index-DYc-B93N.js +28 -0
  84. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/static/assets/react-DB7G9u3x.js +28 -0
  85. controlm_chain_admin-0.1.0/src/controlm_chain_admin/web/static/index.html +16 -0
  86. controlm_chain_admin-0.1.0/tests/__init__.py +0 -0
  87. controlm_chain_admin-0.1.0/tests/conftest.py +45 -0
  88. controlm_chain_admin-0.1.0/tests/realdata/__init__.py +0 -0
  89. controlm_chain_admin-0.1.0/tests/realdata/test_compare_real.py +48 -0
  90. controlm_chain_admin-0.1.0/tests/realdata/test_constants_real.py +51 -0
  91. controlm_chain_admin-0.1.0/tests/realdata/test_dedupe_real.py +45 -0
  92. controlm_chain_admin-0.1.0/tests/realdata/test_environments.py +65 -0
  93. controlm_chain_admin-0.1.0/tests/realdata/test_export_file.py +37 -0
  94. controlm_chain_admin-0.1.0/tests/realdata/test_fixes_real.py +49 -0
  95. controlm_chain_admin-0.1.0/tests/realdata/test_import_export.py +56 -0
  96. controlm_chain_admin-0.1.0/tests/realdata/test_package_real.py +51 -0
  97. controlm_chain_admin-0.1.0/tests/realdata/test_refactor_real.py +49 -0
  98. controlm_chain_admin-0.1.0/tests/realdata/test_roundtrip.py +33 -0
  99. controlm_chain_admin-0.1.0/tests/realdata/test_table_real.py +40 -0
  100. controlm_chain_admin-0.1.0/tests/realdata/test_validate_real.py +50 -0
  101. controlm_chain_admin-0.1.0/tests/support/__init__.py +0 -0
  102. controlm_chain_admin-0.1.0/tests/support/anomalies.py +64 -0
  103. controlm_chain_admin-0.1.0/tests/support/envexports.py +72 -0
  104. controlm_chain_admin-0.1.0/tests/support/gitrepo.py +70 -0
  105. controlm_chain_admin-0.1.0/tests/support/rawxml.py +71 -0
  106. controlm_chain_admin-0.1.0/tests/support/samples.py +39 -0
  107. controlm_chain_admin-0.1.0/tests/unit/__init__.py +0 -0
  108. controlm_chain_admin-0.1.0/tests/unit/test_attribute_groups.py +25 -0
  109. controlm_chain_admin-0.1.0/tests/unit/test_cli.py +46 -0
  110. controlm_chain_admin-0.1.0/tests/unit/test_cli_commands.py +137 -0
  111. controlm_chain_admin-0.1.0/tests/unit/test_cli_commit.py +53 -0
  112. controlm_chain_admin-0.1.0/tests/unit/test_cli_compare.py +94 -0
  113. controlm_chain_admin-0.1.0/tests/unit/test_cli_distinct_filter.py +56 -0
  114. controlm_chain_admin-0.1.0/tests/unit/test_cli_env.py +97 -0
  115. controlm_chain_admin-0.1.0/tests/unit/test_cli_inspect.py +99 -0
  116. controlm_chain_admin-0.1.0/tests/unit/test_cli_package.py +107 -0
  117. controlm_chain_admin-0.1.0/tests/unit/test_cli_receive.py +154 -0
  118. controlm_chain_admin-0.1.0/tests/unit/test_cli_refactor.py +201 -0
  119. controlm_chain_admin-0.1.0/tests/unit/test_cli_release.py +88 -0
  120. controlm_chain_admin-0.1.0/tests/unit/test_cli_resolve.py +60 -0
  121. controlm_chain_admin-0.1.0/tests/unit/test_cli_serve.py +55 -0
  122. controlm_chain_admin-0.1.0/tests/unit/test_commit.py +151 -0
  123. controlm_chain_admin-0.1.0/tests/unit/test_compare.py +262 -0
  124. controlm_chain_admin-0.1.0/tests/unit/test_constants.py +198 -0
  125. controlm_chain_admin-0.1.0/tests/unit/test_constants_ops.py +316 -0
  126. controlm_chain_admin-0.1.0/tests/unit/test_constants_overview.py +28 -0
  127. controlm_chain_admin-0.1.0/tests/unit/test_dedupe.py +197 -0
  128. controlm_chain_admin-0.1.0/tests/unit/test_edit_ops.py +262 -0
  129. controlm_chain_admin-0.1.0/tests/unit/test_env_rule.py +133 -0
  130. controlm_chain_admin-0.1.0/tests/unit/test_fixes.py +238 -0
  131. controlm_chain_admin-0.1.0/tests/unit/test_graph.py +87 -0
  132. controlm_chain_admin-0.1.0/tests/unit/test_history.py +112 -0
  133. controlm_chain_admin-0.1.0/tests/unit/test_inspect.py +82 -0
  134. controlm_chain_admin-0.1.0/tests/unit/test_intake.py +127 -0
  135. controlm_chain_admin-0.1.0/tests/unit/test_intake_envs.py +153 -0
  136. controlm_chain_admin-0.1.0/tests/unit/test_intake_groups.py +180 -0
  137. controlm_chain_admin-0.1.0/tests/unit/test_jsonmodel.py +150 -0
  138. controlm_chain_admin-0.1.0/tests/unit/test_letter.py +171 -0
  139. controlm_chain_admin-0.1.0/tests/unit/test_links.py +140 -0
  140. controlm_chain_admin-0.1.0/tests/unit/test_links_truth.py +230 -0
  141. controlm_chain_admin-0.1.0/tests/unit/test_main_module.py +20 -0
  142. controlm_chain_admin-0.1.0/tests/unit/test_membership.py +62 -0
  143. controlm_chain_admin-0.1.0/tests/unit/test_overrides.py +184 -0
  144. controlm_chain_admin-0.1.0/tests/unit/test_package.py +277 -0
  145. controlm_chain_admin-0.1.0/tests/unit/test_packaging.py +49 -0
  146. controlm_chain_admin-0.1.0/tests/unit/test_rawxml.py +50 -0
  147. controlm_chain_admin-0.1.0/tests/unit/test_receive.py +131 -0
  148. controlm_chain_admin-0.1.0/tests/unit/test_refactor.py +349 -0
  149. controlm_chain_admin-0.1.0/tests/unit/test_relations.py +80 -0
  150. controlm_chain_admin-0.1.0/tests/unit/test_repo_ops.py +218 -0
  151. controlm_chain_admin-0.1.0/tests/unit/test_selection.py +138 -0
  152. controlm_chain_admin-0.1.0/tests/unit/test_take.py +179 -0
  153. controlm_chain_admin-0.1.0/tests/unit/test_validate.py +142 -0
  154. controlm_chain_admin-0.1.0/tests/unit/test_validate_names.py +145 -0
  155. controlm_chain_admin-0.1.0/tests/unit/test_workspace.py +470 -0
  156. controlm_chain_admin-0.1.0/tests/unit/test_xmlio.py +144 -0
  157. controlm_chain_admin-0.1.0/tests/web/__init__.py +0 -0
  158. controlm_chain_admin-0.1.0/tests/web/conftest.py +38 -0
  159. controlm_chain_admin-0.1.0/tests/web/openapi.snapshot.json +4613 -0
  160. controlm_chain_admin-0.1.0/tests/web/test_api.py +167 -0
  161. controlm_chain_admin-0.1.0/tests/web/test_api_commit.py +73 -0
  162. controlm_chain_admin-0.1.0/tests/web/test_api_compare.py +64 -0
  163. controlm_chain_admin-0.1.0/tests/web/test_api_edit.py +107 -0
  164. controlm_chain_admin-0.1.0/tests/web/test_api_environments.py +30 -0
  165. controlm_chain_admin-0.1.0/tests/web/test_api_intake.py +98 -0
  166. controlm_chain_admin-0.1.0/tests/web/test_api_package.py +116 -0
  167. controlm_chain_admin-0.1.0/tests/web/test_api_take.py +83 -0
  168. controlm_chain_admin-0.1.0/tests/web/test_api_workspace.py +163 -0
  169. controlm_chain_admin-0.1.0/tests/web/test_openapi.py +31 -0
  170. controlm_chain_admin-0.1.0/tests/web/test_static_ui.py +60 -0
  171. controlm_chain_admin-0.1.0/web/.prettierrc +6 -0
  172. controlm_chain_admin-0.1.0/web/eslint.config.js +22 -0
  173. controlm_chain_admin-0.1.0/web/index.html +13 -0
  174. controlm_chain_admin-0.1.0/web/package-lock.json +6864 -0
  175. controlm_chain_admin-0.1.0/web/package.json +56 -0
  176. controlm_chain_admin-0.1.0/web/scripts/dump_fixtures.py +261 -0
  177. controlm_chain_admin-0.1.0/web/src/app/App.tsx +89 -0
  178. controlm_chain_admin-0.1.0/web/src/components/DiffView.tsx +28 -0
  179. controlm_chain_admin-0.1.0/web/src/components/EffectsTable.tsx +56 -0
  180. controlm_chain_admin-0.1.0/web/src/components/ui.tsx +226 -0
  181. controlm_chain_admin-0.1.0/web/src/features/chain-table/ChainTablePage.test.tsx +67 -0
  182. controlm_chain_admin-0.1.0/web/src/features/chain-table/ChainTablePage.tsx +211 -0
  183. controlm_chain_admin-0.1.0/web/src/features/changes/ChangeProvider.test.tsx +105 -0
  184. controlm_chain_admin-0.1.0/web/src/features/changes/ChangeProvider.tsx +170 -0
  185. controlm_chain_admin-0.1.0/web/src/features/changes/TokenForm.tsx +37 -0
  186. controlm_chain_admin-0.1.0/web/src/features/changes/changes-context.ts +20 -0
  187. controlm_chain_admin-0.1.0/web/src/features/commit/CommitButton.test.tsx +68 -0
  188. controlm_chain_admin-0.1.0/web/src/features/commit/CommitButton.tsx +26 -0
  189. controlm_chain_admin-0.1.0/web/src/features/commit/CommitDialog.tsx +137 -0
  190. controlm_chain_admin-0.1.0/web/src/features/commit/branch-name.ts +12 -0
  191. controlm_chain_admin-0.1.0/web/src/features/compare/CommitPicker.tsx +85 -0
  192. controlm_chain_admin-0.1.0/web/src/features/compare/ComparePage.test.tsx +423 -0
  193. controlm_chain_admin-0.1.0/web/src/features/compare/ComparePage.tsx +844 -0
  194. controlm_chain_admin-0.1.0/web/src/features/compare/CopyMarkdownButton.tsx +56 -0
  195. controlm_chain_admin-0.1.0/web/src/features/compare/PackagePanel.tsx +213 -0
  196. controlm_chain_admin-0.1.0/web/src/features/compare/TakeBar.tsx +170 -0
  197. controlm_chain_admin-0.1.0/web/src/features/compare/refs.ts +29 -0
  198. controlm_chain_admin-0.1.0/web/src/features/compare/take-context.ts +19 -0
  199. controlm_chain_admin-0.1.0/web/src/features/editing/AttributeForm.tsx +111 -0
  200. controlm_chain_admin-0.1.0/web/src/features/editing/InlineAction.tsx +49 -0
  201. controlm_chain_admin-0.1.0/web/src/features/editing/RawJsonEditor.tsx +44 -0
  202. controlm_chain_admin-0.1.0/web/src/features/editing/RelationsEditor.test.tsx +97 -0
  203. controlm_chain_admin-0.1.0/web/src/features/editing/RelationsEditor.tsx +367 -0
  204. controlm_chain_admin-0.1.0/web/src/features/editing/VariablesEditor.tsx +68 -0
  205. controlm_chain_admin-0.1.0/web/src/features/editing/editors.test.tsx +140 -0
  206. controlm_chain_admin-0.1.0/web/src/features/editing/labels.ts +8 -0
  207. controlm_chain_admin-0.1.0/web/src/features/environments/EnvironmentsPage.test.tsx +69 -0
  208. controlm_chain_admin-0.1.0/web/src/features/environments/EnvironmentsPage.tsx +195 -0
  209. controlm_chain_admin-0.1.0/web/src/features/exceptions/ExceptionsPanel.test.tsx +81 -0
  210. controlm_chain_admin-0.1.0/web/src/features/exceptions/ExceptionsPanel.tsx +147 -0
  211. controlm_chain_admin-0.1.0/web/src/features/exceptions/exception-count.ts +9 -0
  212. controlm_chain_admin-0.1.0/web/src/features/folder-graph/FolderGraph.tsx +62 -0
  213. controlm_chain_admin-0.1.0/web/src/features/folder-graph/FolderPage.test.tsx +41 -0
  214. controlm_chain_admin-0.1.0/web/src/features/folder-graph/FolderPage.tsx +270 -0
  215. controlm_chain_admin-0.1.0/web/src/features/folder-graph/flow.test.ts +38 -0
  216. controlm_chain_admin-0.1.0/web/src/features/folder-graph/flow.ts +54 -0
  217. controlm_chain_admin-0.1.0/web/src/features/intake/ImportPage.test.tsx +195 -0
  218. controlm_chain_admin-0.1.0/web/src/features/intake/ImportPage.tsx +413 -0
  219. controlm_chain_admin-0.1.0/web/src/features/job-detail/JobPage.test.tsx +73 -0
  220. controlm_chain_admin-0.1.0/web/src/features/job-detail/JobPage.tsx +176 -0
  221. controlm_chain_admin-0.1.0/web/src/features/repo/RepoBadge.test.tsx +24 -0
  222. controlm_chain_admin-0.1.0/web/src/features/repo/RepoBadge.tsx +22 -0
  223. controlm_chain_admin-0.1.0/web/src/features/validate/FixOptions.tsx +64 -0
  224. controlm_chain_admin-0.1.0/web/src/features/validate/ResolvePanel.tsx +143 -0
  225. controlm_chain_admin-0.1.0/web/src/features/validate/ValidatePage.test.tsx +132 -0
  226. controlm_chain_admin-0.1.0/web/src/features/validate/ValidatePage.tsx +250 -0
  227. controlm_chain_admin-0.1.0/web/src/features/workspace/BranchButton.test.tsx +160 -0
  228. controlm_chain_admin-0.1.0/web/src/features/workspace/BranchButton.tsx +28 -0
  229. controlm_chain_admin-0.1.0/web/src/features/workspace/ProtectedBanner.tsx +21 -0
  230. controlm_chain_admin-0.1.0/web/src/features/workspace/ReadOnlyNotice.tsx +32 -0
  231. controlm_chain_admin-0.1.0/web/src/features/workspace/WorkspaceDialog.tsx +384 -0
  232. controlm_chain_admin-0.1.0/web/src/features/workspace/plural.ts +3 -0
  233. controlm_chain_admin-0.1.0/web/src/features/workspace/use-workspace-action.ts +14 -0
  234. controlm_chain_admin-0.1.0/web/src/index.css +99 -0
  235. controlm_chain_admin-0.1.0/web/src/lib/api/client.ts +112 -0
  236. controlm_chain_admin-0.1.0/web/src/lib/api/queries.ts +135 -0
  237. controlm_chain_admin-0.1.0/web/src/lib/api/session.test.ts +14 -0
  238. controlm_chain_admin-0.1.0/web/src/lib/api/session.ts +34 -0
  239. controlm_chain_admin-0.1.0/web/src/lib/api/types.gen.ts +2989 -0
  240. controlm_chain_admin-0.1.0/web/src/lib/layout.ts +30 -0
  241. controlm_chain_admin-0.1.0/web/src/lib/utils.test.ts +32 -0
  242. controlm_chain_admin-0.1.0/web/src/lib/utils.ts +42 -0
  243. controlm_chain_admin-0.1.0/web/src/main.tsx +17 -0
  244. controlm_chain_admin-0.1.0/web/src/test/fixtures/compare-selected.json +448 -0
  245. controlm_chain_admin-0.1.0/web/src/test/fixtures/compare.json +993 -0
  246. controlm_chain_admin-0.1.0/web/src/test/fixtures/environments.json +71 -0
  247. controlm_chain_admin-0.1.0/web/src/test/fixtures/folder-P77_CHAIN.json +318 -0
  248. controlm_chain_admin-0.1.0/web/src/test/fixtures/folder-P77_INGEST_DAILY.json +133 -0
  249. controlm_chain_admin-0.1.0/web/src/test/fixtures/folders.json +19 -0
  250. controlm_chain_admin-0.1.0/web/src/test/fixtures/git.json +29 -0
  251. controlm_chain_admin-0.1.0/web/src/test/fixtures/intake-full.json +101 -0
  252. controlm_chain_admin-0.1.0/web/src/test/fixtures/intake-groups.json +170 -0
  253. controlm_chain_admin-0.1.0/web/src/test/fixtures/intake.json +100 -0
  254. controlm_chain_admin-0.1.0/web/src/test/fixtures/job-P77_CHAIN-P77_B.json +158 -0
  255. controlm_chain_admin-0.1.0/web/src/test/fixtures/job-P77_INGEST_DAILY-P77_INGEST_LOAD.json +132 -0
  256. controlm_chain_admin-0.1.0/web/src/test/fixtures/package.json +98 -0
  257. controlm_chain_admin-0.1.0/web/src/test/fixtures/pending.json +35 -0
  258. controlm_chain_admin-0.1.0/web/src/test/fixtures/preview.json +12 -0
  259. controlm_chain_admin-0.1.0/web/src/test/fixtures/repo.json +11 -0
  260. controlm_chain_admin-0.1.0/web/src/test/fixtures/table.json +233 -0
  261. controlm_chain_admin-0.1.0/web/src/test/fixtures/validate.json +440 -0
  262. controlm_chain_admin-0.1.0/web/src/test/fixtures/workspace-main.json +18 -0
  263. controlm_chain_admin-0.1.0/web/src/test/fixtures/workspace.json +54 -0
  264. controlm_chain_admin-0.1.0/web/src/test/render.tsx +32 -0
  265. controlm_chain_admin-0.1.0/web/src/test/server.ts +139 -0
  266. controlm_chain_admin-0.1.0/web/src/test/setup.ts +40 -0
  267. controlm_chain_admin-0.1.0/web/tsconfig.json +25 -0
  268. controlm_chain_admin-0.1.0/web/vite.config.ts +43 -0
@@ -0,0 +1,41 @@
1
+ # Attribution
2
+
3
+ The skills under `.claude/skills/` were written for this project and adapt material from
4
+ **Everything Claude Code (ECC)** by Affaan Mustafa — <https://github.com/affaan-m/everything-claude-code>,
5
+ released under the MIT License. Adapted components:
6
+
7
+ | Skill here | Adapted from ECC |
8
+ |---|---|
9
+ | `verify` | `skills/verification-loop` |
10
+ | `oss-repo-standards` | `agents/opensource-packager`, `agents/opensource-sanitizer`, `rules/common/*` |
11
+ | `python-core-tdd` | `skills/tdd-workflow`, `skills/python-testing`, `agents/python-reviewer`, `rules/python/*` |
12
+ | `fastapi-api` | `skills/fastapi-patterns`, `agents/fastapi-reviewer`, `rules/python/fastapi.md` |
13
+ | `react-frontend` | `skills/react-patterns`, `skills/react-testing`, `skills/vite-patterns`, `rules/react/*`, `rules/typescript/*`, `rules/web/*` |
14
+
15
+ The adaptations are specific to this repository (stdlib-only core, one-core-two-adapters,
16
+ no-real-data rule, synthetic fixtures); they are not a redistribution of ECC. ECC's licence
17
+ text follows.
18
+
19
+ ## Everything Claude Code — MIT License
20
+
21
+ MIT License
22
+
23
+ Copyright (c) 2026 Affaan Mustafa
24
+
25
+ Permission is hereby granted, free of charge, to any person obtaining a copy
26
+ of this software and associated documentation files (the "Software"), to deal
27
+ in the Software without restriction, including without limitation the rights
28
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29
+ copies of the Software, and to permit persons to whom the Software is
30
+ furnished to do so, subject to the following conditions:
31
+
32
+ The above copyright notice and this permission notice shall be included in all
33
+ copies or substantial portions of the Software.
34
+
35
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
41
+ SOFTWARE.
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: bootstrap
3
+ description: Set up controlm-chain-admin where only PyPI is reachable (no GitHub), then build a new chain repository from the full exports of every environment, step by step, with the conventions agreed for environments, constants and exceptions. Use when someone says «instalar na empresa», «set up at work», «criar o repositório de dados», «começar do zero», «bootstrap», or opens this source for the first time on a new machine.
4
+ ---
5
+
6
+ # bootstrap — the code from PyPI, the data repository from the exports
7
+
8
+ Two separate directories, never one inside the other:
9
+
10
+ - **the code**: this project, unpacked from its source distribution, to run and adjust;
11
+ - **the data**: a new git repository with the chains of one application, built from the
12
+ exports. It holds real data and never mixes with the code.
13
+
14
+ Ask the person before anything that is hard to undo (pushing, deleting, `--apply` on many
15
+ files) and number every question so they can answer «1 sim, 2 não».
16
+
17
+ ## Part A — the code
18
+
19
+ 1. Check what the machine has: `python --version` (3.11 or newer), `git --version`, and
20
+ whether `pip download` reaches PyPI (or the company mirror). npm is only needed to change
21
+ the web UI; the built UI already ships in the package.
22
+ 2. Unpack the source and make it a git repository of its own (adjustments made here stay
23
+ here; the next version brings them back from upstream):
24
+
25
+ ```bash
26
+ pip download controlm-chain-admin==<version> --no-deps --no-binary :all:
27
+ tar -xzf controlm_chain_admin-<version>.tar.gz
28
+ cd controlm_chain_admin-<version>
29
+ git init -b main && git add -A && git commit -m "chore: controlm-chain-admin <version>"
30
+ python -m venv .venv
31
+ .venv/bin/pip install -e ".[dev,web]" # Windows: .venv\Scripts\pip ...
32
+ ```
33
+
34
+ 3. Create `.claude/no-real-data.patterns` (git-ignored, one regular expression per line) with
35
+ the names that must never enter this code: the company, its domains, the application
36
+ code, machine and user prefixes. Ask the person for them. The gate scans for them.
37
+ 4. Run the gate once: `PATH="$PWD/.venv/bin:$PATH" .claude/skills/verify/verify.sh` (on
38
+ Windows from Git Bash, with `.venv/Scripts`). Without npm the frontend steps are skipped.
39
+ 5. From here on the project rules apply (`CLAUDE.md`): TDD, English in the code, no real data
40
+ in this directory, not even in tests.
41
+
42
+ ## Part B — the data repository
43
+
44
+ ### 1. What the exports say
45
+
46
+ Put the full exports in `exports/<env>/` of the new data directory (they are big: look at
47
+ them with scripts and counts, never whole). Then ask, numbered, what the exports do not say:
48
+
49
+ 1. the application (`APPLICATION` of its folders) and the environments with their letters,
50
+ e.g. `test=T,uat=U,bench=B,prod=P`;
51
+ 2. the bare prefixes of the letter rule (the application code, `RQ_`, `RC_`) and which of
52
+ them carry the letter on their first token only (`--leading-only RQ_,RC_`: resources such
53
+ as `URQ_P77_AGGREGATION`);
54
+ 3. which environment is production (default `prod`).
55
+
56
+ ### 2. Production first: it is the trunk
57
+
58
+ ```bash
59
+ mkdir chains && cd chains && git init -b main
60
+ ctmchain init --application <APP> --envs test=T,uat=U,bench=B,prod=P \
61
+ --prefixes P77,RQ_,RC_ --leading-only RQ_,RC_
62
+ ctmchain import ../exports/prod/<prod>.xml --env prod --dedupe-jobnames
63
+ ctmchain export --env prod --jobnames original -o /tmp/prod-check.xml
64
+ cmp /tmp/prod-check.xml ../exports/prod/<prod>.xml && echo "prod: byte for byte"
65
+ git add -A && git commit -m "chore: production baseline"
66
+ ```
67
+
68
+ This first commit is the only one made on `main` by hand: from now on `main` mirrors
69
+ production and every change goes through a release.
70
+
71
+ ### 3. The other environments, one release
72
+
73
+ ```bash
74
+ ctmchain release start baseline
75
+ ctmchain receive ../exports/uat/<uat>.xml --full # preview: the decisions
76
+ ```
77
+
78
+ A full export of an environment other than production leaves production alone by default.
79
+ Read the decisions with the person, by section, before `--apply`:
80
+
81
+ - **groups** (the same difference in many jobs, or a machine, user, mail or variable): a new
82
+ constant with a value per environment. Give them readable names with
83
+ `--choose 'group:...=new:<name>'`, or in the *Import* page of `ctmchain serve`.
84
+ - **exceptions** (a value that differs in one job), **children** (conditions or ON blocks
85
+ that differ: ignored by default), **removed / added / absent** (jobs and folders only one
86
+ environment has or lacks).
87
+
88
+ Then `--apply`, `ctmchain export --env uat` to look at the result, and commit. Same for bench
89
+ and test. Receiving the same export again shows what still differs.
90
+
91
+ ### 4. The conventions agreed for these chains
92
+
93
+ - **Machines**: neutral names by order, `node.bat1` (first) and `node.bat2` (second); each
94
+ environment has its own machines behind them.
95
+ - **Users**: `user.<role>_user_proc`, e.g. `user.batch_user_proc`, `user.per_user_proc`. A
96
+ value that fits none: ask whether it is an existing one (`use:<name>`) or a new one (e.g.
97
+ `user.lala_user_proc`).
98
+ - **Mails, transfer (CFT) settings, variables such as the environment code**: one value per
99
+ environment (a constant), which a single job may still change (an exception).
100
+ - **Time windows, MAXWAIT, calendars, file age limits**: the same everywhere; a difference is
101
+ an exception for that job, after asking.
102
+ - **TASKTYPE Dummy, another CMDLINE in one environment**: exceptions of that environment.
103
+ - **Dirty names** (another environment's letter in a condition, a resource of another
104
+ environment, a letter in place of the application's first letter): not fixed on the way
105
+ in. `ctmchain validate` lists them with suggested fixes, to correct in later releases.
106
+
107
+ ### 5. Close the baseline
108
+
109
+ ```bash
110
+ ctmchain release installed prod # nothing to install: the baseline only describes them
111
+ ctmchain release close
112
+ ```
113
+
114
+ Then the everyday flow of the data repository's own `CLAUDE.md` (written by `init`):
115
+ deliveries through `ctmchain receive`, a full prod export now and then to catch up with
116
+ production, releases installed environment by environment.
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: fastapi-api
3
+ description: Standards for the local FastAPI server of controlm-chain-admin (src/controlm_chain_admin/web, the [web] extra, `ctmchain serve`). Use for any change to API routers, schemas, dependencies, error handling, OpenAPI metadata or API tests, and when someone asks to «criar endpoint», «expor na API», «servir», or review the API. Thin handlers over the core, typed errors, TestClient tests, OpenAPI snapshot.
4
+ ---
5
+
6
+ # fastapi-api
7
+
8
+ Adapted from Everything Claude Code `fastapi-patterns`, `fastapi-reviewer` and
9
+ `rules/python/fastapi.md` (MIT, see `.claude/ATTRIBUTION.md`). Architecture: `DESIGN.md` §11.
10
+
11
+ ## Structure
12
+
13
+ ```text
14
+ src/controlm_chain_admin/web/
15
+ app.py # create_app(settings) -> FastAPI; lifespan loads ChainRepo; mounts static SPA
16
+ settings.py # repo path, host (127.0.0.1), port, token, open_browser
17
+ deps.py # get_repo() (reloads when files changed), require_token()
18
+ errors.py # ONE exception handler: core typed errors -> HTTP status + {"error","message","detail"}
19
+ schemas/ # Pydantic v2 response/request models, one module per resource
20
+ routers/ # repo.py folders.py jobs.py links.py validate.py changes.py
21
+ static/ # built SPA (web/dist), served at "/" (not committed)
22
+ ```
23
+
24
+ ## Rules
25
+
26
+ - **Handlers are thin**: parse → call one `core` function → return a schema. No loops over
27
+ folders, no name logic, no file access in a router. If a handler needs a rule, the rule goes
28
+ to `core` and the CLI gets it too.
29
+ - The core is synchronous and in-memory, so handlers are plain `def` (FastAPI runs them in a
30
+ threadpool). Use `async def` only for handlers that await something. Never block an `async`
31
+ handler with file or subprocess calls.
32
+ - `response_model` on every endpoint; separate request, response and list schemas; schemas
33
+ mirror `core` dataclasses (build them with `model_validate(dataclasses.asdict(...))` or
34
+ `from_attributes`), never expose internals the UI does not need.
35
+ - Pagination (`limit`, `offset`) on every list endpoint even if the UI does not use it yet.
36
+ - Errors: `core` typed errors map in `errors.py` only — `NotFound` 404, `NameCollision`/
37
+ `LiteralCollision` 409, `UnresolvedConstant`/`DanglingLink` 422, unexpected 500 with a log
38
+ line and no stack trace in the body. Every error response has the same shape.
39
+ - Mutations (`POST/PUT/DELETE`) are `/api/changes/*`: preview returns a `ChangeSet`, apply takes
40
+ the same `ChangeSet` back. Both require the `X-Ctmchain-Token` header checked by
41
+ `require_token`. `GET` endpoints are read-only and need no token.
42
+ - Bind `127.0.0.1` by default; `--host` must be explicit; CORS off (same origin: the SPA is
43
+ served by the same app). Log the request line, never request bodies.
44
+ - OpenAPI: `title`, `version` from the package, a tag per router with a description, every
45
+ endpoint has `summary` and documented error responses. The schema is the frontend contract
46
+ (`web/` generates TypeScript types from it), so changing it is a visible diff.
47
+ - Configuration via `settings.py` (pydantic-settings) with env prefix `CTMCHAIN_`; no reading
48
+ `os.environ` in routers.
49
+
50
+ ## Tests (TDD, like everything else)
51
+
52
+ - `tests/web/conftest.py` builds a fixture chain repo in `tmp_path`, overrides `get_repo` with
53
+ `app.dependency_overrides`, clears it after the test, and yields a `TestClient`.
54
+ - One test module per router; assert status, body shape and the exact values from the
55
+ fixture; one negative test per error mapping; one test proving a mutation without the token
56
+ is 401 and with the token returns the preview.
57
+ - `tests/web/test_openapi.py` compares `app.openapi()` with
58
+ `tests/web/openapi.snapshot.json`; updating the snapshot is a deliberate commit.
59
+ - No network, no real data, no sleeping; the server is never started in tests.
60
+
61
+ ## Verify
62
+
63
+ 1. `pytest tests/web -q` green, including the OpenAPI snapshot.
64
+ 2. Checklist (from `fastapi-reviewer`): no logic in handlers · `response_model` everywhere ·
65
+ one error handler, consistent error shape · token on every mutation · no `async def`
66
+ doing blocking work · list endpoints paginated · settings only via `settings.py` ·
67
+ no secrets, hosts or real names in code or snapshot · docs tags and summaries present.
68
+ 3. Start it once by hand: `ctmchain serve --repo <fixture repo> --no-browser`, open
69
+ `/docs`, call two endpoints, stop it.
70
+ 4. Finish with the `verify` skill and paste its report in the PR.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: oss-repo-standards
3
+ description: Open-source repository standards for controlm-chain-admin — README structure, community health files, Conventional Commits, Keep a Changelog, SemVer, issue/PR templates, Trusted Publishing release, naming conventions, bilingual mkdocs. Use when creating or editing README, CONTRIBUTING, CHANGELOG, docs, pyproject metadata, GitHub workflows or templates, when naming a module, command or JSON key, or when someone asks whether the repo «segue os padrões open source».
4
+ ---
5
+
6
+ # oss-repo-standards
7
+
8
+ Adapted from Everything Claude Code `opensource-packager`, `opensource-sanitizer` and
9
+ `rules/common` (MIT, see `.claude/ATTRIBUTION.md`), and from the author's `xmldiffreport`.
10
+
11
+ ## Files every release must have
12
+
13
+ | File | Standard |
14
+ |---|---|
15
+ | `README.md` | See structure below |
16
+ | `LICENSE` | MIT, copyright line with year and author |
17
+ | `CONTRIBUTING.md` | how to set up, run tests, TDD rule, commit format, PR checklist, where to ask |
18
+ | `CODE_OF_CONDUCT.md` | Contributor Covenant 2.1 with a contact address |
19
+ | `SECURITY.md` | supported versions, private reporting channel, response time |
20
+ | `CHANGELOG.md` | Keep a Changelog 1.1: `## [Unreleased]` on top, sections Added/Changed/Fixed/Removed, compare links |
21
+ | `.github/ISSUE_TEMPLATE/bug_report.md`, `feature_request.md`, `.github/PULL_REQUEST_TEMPLATE.md` | PR template includes the `verify` report and the TDD checkbox |
22
+ | `.github/workflows/ci.yml`, `release.yml`, `docs.yml` | CI on push/PR (lint + test matrix 3.11–3.13, macOS/Windows), release on `v*` tags with PyPI Trusted Publishing (OIDC, environment `pypi`), docs to GitHub Pages |
23
+ | `.editorconfig`, `.pre-commit-config.yaml` | ruff, ruff-format, end-of-file, trailing whitespace |
24
+ | `pyproject.toml` | name, version (single source), description, readme, `requires-python`, license, authors, keywords, classifiers (Development Status, Intended Audience, License, OS, Python versions, Topic, Typing :: Typed), `[project.urls]` Homepage/Documentation/Repository/Issues/Changelog, `[project.scripts] ctmchain` |
25
+ | `mkdocs.yml` | mkdocs-material, `mkdocs-static-i18n` with `en` default and `pt`, every page has a `.pt.md` twin |
26
+
27
+ ## README structure (in this order)
28
+
29
+ 1. Title, one-line tagline, badges: Docs, CI, PyPI version, Python versions, License.
30
+ 2. Documentation links (English and Português).
31
+ 3. One paragraph: what it is, for whom, the problem it solves (Control-M XML exports are hard
32
+ to manage; JSON in git, links as first-class, environment-neutral base).
33
+ 4. Why not X: short comparison with the Control-M UI, Automation API JSON, raw XML + git.
34
+ 5. Install (`pip install controlm-chain-admin`, `[web]` extra) and requirements.
35
+ 6. Quickstart: `init`, `distinct`, `import`, `validate`, `export`, `serve` in 10 lines, with
36
+ the synthetic fixture so the reader can run it without real data.
37
+ 7. Concepts in a small table (chain repository, base, environment, link, constant, override).
38
+ 8. Status / roadmap pointer to `BACKLOG.md`, Contributing pointer, Licence.
39
+
40
+ No real data in any example: application `P77`, hosts `srvu-p77-*`, addresses `@example.com`.
41
+
42
+ ## Conventions
43
+
44
+ - **Commits**: Conventional Commits (`feat:`, `fix:`, `docs:`, `test:`, `refactor:`, `chore:`,
45
+ `ci:`), imperative, ≤ 72 chars subject, body explains why. Breaking change → `!` and footer.
46
+ - **Versions**: SemVer; `0.x` while the JSON layout may change; tag `vX.Y.Z` = release.
47
+ - **Branches**: `main` protected by CI; short-lived `feat/<topic>`, `fix/<topic>`.
48
+ - **Python names**: package `controlm_chain_admin`, modules and functions `snake_case`,
49
+ classes `PascalCase`, constants `UPPER_SNAKE`, private `_leading_underscore`.
50
+ - **CLI**: command `ctmchain`, subcommands kebab-case (`rename-job`), flags `--kebab-case`.
51
+ - **JSON keys**: attributes mirrored from Control-M XML keep their exact XML name
52
+ (`JOBNAME`, `SUB_APPLICATION`) for fidelity; keys that belong to this tool are
53
+ `snake_case` (`envs`, `links`, `cleanup`, `external`).
54
+ - **Docs**: English first, Portuguese twin, same headings; code blocks copy-pasteable.
55
+ - **Issues/PRs**: labels `bug`, `enhancement`, `docs`, `good first issue`; PR title in
56
+ Conventional Commits form.
57
+
58
+ ## Verify
59
+
60
+ 1. Run `.claude/skills/oss-repo-standards/check_repo.sh`; it lists missing files/sections and
61
+ checks the last 20 commit subjects against Conventional Commits. All items `OK` or an
62
+ accepted `TODO` with the backlog story that will add it.
63
+ 2. `gh api repos/{owner}/{repo}/community/profile --jq .health_percentage` must be `100`
64
+ once the files exist.
65
+ 3. Read the README top to bottom as a stranger: can they install and run the quickstart in
66
+ five minutes without asking anything? Every command copy-pasteable and tested.
67
+ 4. Grep the docs for anything that looks like real data (see `verify`'s no-real-data phase).
68
+ 5. Finish with the `verify` skill and paste its report in the PR.
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env bash
2
+ # check_repo.sh — open-source hygiene checklist for controlm-chain-admin. Prints OK/MISSING per item.
3
+ set -uo pipefail
4
+ cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
5
+ MISSING=0
6
+ ok() { printf 'OK %s\n' "$1"; }
7
+ miss() { printf 'MISSING %s\n' "$1"; MISSING=$((MISSING+1)); }
8
+ has_file() { [ -e "$1" ] && ok "$1" || miss "$1"; }
9
+ has_section() { [ -f "$1" ] && grep -qiE "$2" "$1" && ok "$1: $3" || miss "$1: $3"; }
10
+
11
+ echo "== community files"
12
+ for f in README.md LICENSE CONTRIBUTING.md CODE_OF_CONDUCT.md SECURITY.md CHANGELOG.md \
13
+ .github/ISSUE_TEMPLATE/bug_report.md .github/ISSUE_TEMPLATE/feature_request.md \
14
+ .github/PULL_REQUEST_TEMPLATE.md .github/workflows/ci.yml .github/workflows/release.yml \
15
+ .editorconfig .pre-commit-config.yaml pyproject.toml mkdocs.yml; do has_file "$f"; done
16
+
17
+ echo "== README sections"
18
+ has_section README.md 'img.shields.io|badge' "badges"
19
+ has_section README.md '^## .*(install|instala)' "Install section"
20
+ has_section README.md '^## .*(quick ?start|usage|getting started)' "Quickstart section"
21
+ has_section README.md 'contribut' "Contributing pointer"
22
+ has_section README.md '^## .*licen[cs]e|MIT' "Licence"
23
+
24
+ echo "== changelog / metadata"
25
+ has_section CHANGELOG.md '^## \[Unreleased\]' "Unreleased section"
26
+ has_section pyproject.toml '^\[project.urls\]' "project.urls"
27
+ has_section pyproject.toml 'classifiers' "classifiers"
28
+ has_section pyproject.toml 'ctmchain *=' "ctmchain script"
29
+ has_section mkdocs.yml 'i18n' "bilingual docs (mkdocs-static-i18n)"
30
+ has_section .github/workflows/release.yml 'id-token: *write' "Trusted Publishing (OIDC)"
31
+
32
+ echo "== commits (last 20 subjects, Conventional Commits)"
33
+ BAD="$(git log -20 --format=%s 2>/dev/null | grep -vE '^(feat|fix|docs|test|refactor|chore|ci|build|perf|style|revert)(\([a-z0-9/_-]+\))?!?: .+' || true)"
34
+ if [ -z "$BAD" ]; then ok "all recent subjects follow Conventional Commits"; else printf 'MISSING non-conventional subjects:\n%s\n' "$BAD" | sed 's/^/ /'; MISSING=$((MISSING+1)); fi
35
+
36
+ echo "== GitHub community profile"
37
+ if command -v gh >/dev/null && gh repo view --json nameWithOwner --jq .nameWithOwner >/dev/null 2>&1; then
38
+ REPO="$(gh repo view --json nameWithOwner --jq .nameWithOwner)"
39
+ PCT="$(gh api "repos/$REPO/community/profile" --jq .health_percentage 2>/dev/null || echo '?')"
40
+ [ "$PCT" = "100" ] && ok "community profile 100%" || printf 'INFO community profile: %s%%\n' "$PCT"
41
+ else
42
+ echo "INFO gh not available or not a GitHub repo; skipped"
43
+ fi
44
+
45
+ echo; [ $MISSING -eq 0 ] && echo "RESULT: OK" || { echo "RESULT: $MISSING item(s) missing"; exit 1; }
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: python-core-tdd
3
+ description: TDD and coding standards for the Python core and CLI of controlm-chain-admin (src/controlm_chain_admin, tests/). Use for any change to Python code — new feature, bug fix, refactor — and when someone asks to «implementar», «corrigir», «testar» or «refatorar» the core, the parser, the serializer, links, validate or the CLI. Enforces test-first, stdlib-only core, one-core-two-adapters, coverage gate.
4
+ ---
5
+
6
+ # python-core-tdd
7
+
8
+ Adapted from Everything Claude Code `tdd-workflow`, `python-testing`, `python-reviewer` and
9
+ `rules/python` (MIT, see `.claude/ATTRIBUTION.md`). Architecture rules come from `DESIGN.md` §11.
10
+
11
+ ## The loop (every change, no exceptions)
12
+
13
+ 1. **Red** — write the test in `tests/` that describes the behaviour; run it; it must fail for
14
+ the right reason (not an import error). Name it after the behaviour:
15
+ `test_export_reproduces_bytes_for_untouched_folder`.
16
+ 2. **Green** — write the smallest code that passes. No extra features.
17
+ 3. **Refactor** — remove duplication, name things, keep functions < 50 lines; tests stay green.
18
+ 4. **Commit** test and code together (`feat:`/`fix:`/`test:`), the test file visible in the diff.
19
+
20
+ A bug fix starts with a failing regression test that reproduces it. If a test must change,
21
+ the behaviour changed on purpose and the commit message says so.
22
+
23
+ ## Test layout
24
+
25
+ ```text
26
+ tests/
27
+ conftest.py # fixture_repo, fixture_xml, tmp chain repos
28
+ fixtures/
29
+ build_fixtures.py # deterministic synthetic export of application P77
30
+ p77_export.xml # committed output of the generator
31
+ unit/test_<module>.py # pure functions, one module per file
32
+ integration/test_cli_*.py # CLI through main(argv), tmp repo, exit codes
33
+ realdata/test_roundtrip.py # @pytest.mark.realdata, skipped unless CTMCHAIN_DATA_REPO is set
34
+ ```
35
+
36
+ - Arrange / Act / Assert, one behaviour per test, `pytest.mark.parametrize` for tables.
37
+ - Fixtures over setup code; `tmp_path` for every file write; never write inside the repo.
38
+ - Byte-level assertions for the serializer (`assert out == original_bytes`), not string
39
+ "looks like" checks. Compare with a filtered original when applications are skipped.
40
+ - `realdata` tests read the private clone path from `CTMCHAIN_DATA_REPO`, never a hardcoded
41
+ path, and never print real values on failure beyond counts and positions.
42
+ - Coverage gate: `fail_under = 90` in `pyproject.toml` for `controlm_chain_admin`; adapters
43
+ (`cli.py`, `web/`) count too, so keep them thin.
44
+
45
+ ## Architecture rules (checked in review)
46
+
47
+ - `core/` imports only the standard library. Third-party code lives in `web/` (`[web]` extra)
48
+ or dev tooling.
49
+ - `core` functions take a loaded `ChainRepo` and parameters, return frozen dataclasses
50
+ (`ChangeSet`, `Report`, resolved nodes) or raise typed errors (`UnresolvedConstant`,
51
+ `DanglingLink`, `NameCollision`, `LiteralCollision`). Nothing in `core` prints or exits.
52
+ - `cli.py` only parses arguments, calls one `core` function, renders (`text|md|json`), maps
53
+ errors to exit codes (0 ok, 1 findings, 2 usage, 3 error).
54
+ - Writes go through `ops.apply(repo, change)`: all files or none; the preview is the same
55
+ object the user saw.
56
+ - Immutability by default: `@dataclass(frozen=True)`, tuples, `Mapping`; build new objects
57
+ instead of mutating. Document order is kept with lists, never with dict insertion assumptions.
58
+ - Determinism: no `datetime.now()` or randomness in model code; the export comment timestamp
59
+ is a parameter.
60
+
61
+ ## Style
62
+
63
+ - Python ≥ 3.11, `from __future__ import annotations` not needed; use `X | None`.
64
+ - Type annotations on every public signature; `mypy src` clean; no `Any` without a comment.
65
+ - `ruff` (line 99; rules E, F, I, UP, B, SIM, C4, RUF) and `ruff format`; no `print` in
66
+ `core`; `logging` for diagnostics; `pathlib` for paths; `with` for every file.
67
+ - Docstrings in English on public modules, classes and functions: one line what, then why if
68
+ non-obvious. Comments explain intent, not mechanics.
69
+ - Errors: catch specific exceptions; never `except: pass`; messages name the folder/job
70
+ identity, never dump a whole element.
71
+ - Encoding: read and write bytes explicitly as UTF-8; never let the platform default decide.
72
+
73
+ ## Verify
74
+
75
+ 1. `pytest -q` green; `pytest -m realdata` green locally when the change touches parsing,
76
+ serialization or links.
77
+ 2. `ruff check . && ruff format --check . && mypy src` clean.
78
+ 3. Checklist: test written first (test file in the diff) · no third-party import under
79
+ `core/` · no `print`/`sys.exit` outside `cli.py` · new behaviour has a byte- or
80
+ value-level assertion · errors typed · no real data in tests or fixtures · functions
81
+ < 50 lines, files < 800 lines · CHANGELOG `Unreleased` updated for user-visible changes.
82
+ 4. Finish with the `verify` skill and paste its report in the PR.
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: react-frontend
3
+ description: Standards for the read-only web UI of controlm-chain-admin (web/, Vite + React + TypeScript + shadcn/ui, TanStack Query, React Flow). Use for any change to .ts/.tsx files, components, pages, API client, tests or the Vite build, and when someone asks to «criar página», «mostrar na UI», «componente», «grafo» or review the frontend. Test-first with Vitest + Testing Library + MSW, OpenAPI-generated types, accessibility, no template look.
4
+ ---
5
+
6
+ # react-frontend
7
+
8
+ Adapted from Everything Claude Code `react-patterns`, `react-testing`, `vite-patterns`,
9
+ `rules/react`, `rules/typescript` and `rules/web` (MIT, see `.claude/ATTRIBUTION.md`).
10
+
11
+ ## Stack and structure
12
+
13
+ ```text
14
+ web/
15
+ package.json # scripts: dev, build, lint, typecheck, test, test:e2e, gen:api
16
+ vite.config.ts # /api proxy to http://127.0.0.1:<port> in dev; outDir dist (git-ignored)
17
+ src/
18
+ app/ # router, providers (QueryClient, theme), layout shell
19
+ features/<area>/ # folders/, folder-graph/, job-detail/, validate/ — components + hooks + tests side by side
20
+ components/ui/ # shadcn/ui primitives (generated, do not hand-edit)
21
+ lib/api/ # client.ts (fetch wrapper), types.gen.ts (openapi-typescript output), queries.ts
22
+ lib/ # utils, formatters
23
+ tests/e2e/ # Playwright smoke against the built app served by ctmchain serve
24
+ ```
25
+
26
+ - TypeScript `strict`; no `any` (use `unknown` and narrow); types for the API come only from
27
+ `npm run gen:api` (openapi-typescript over the FastAPI schema). Never hand-write an API type.
28
+ - Server state only in TanStack Query (`useQuery`/`useSuspenseQuery` with query keys per
29
+ resource); UI state local with `useState`; derived state computed in render, never duplicated.
30
+ - Components: `PascalCase.tsx`, props as `type Props = {...}` destructured in the signature,
31
+ hooks `useX` in `use-x.ts`, boolean props `isX/hasX/canX`, handlers `handleX`, prop `onX`.
32
+ - Imports: react, third-party, `@/` absolute, relative; `import type` for types.
33
+ - Graph: React Flow (`@xyflow/react`) with `dagre` layout computed in a hook; nodes are
34
+ jobs, folder entry/exit pseudo-nodes for folder-level conditions, edge data carries the link
35
+ (name, ODATE, AND_OR, cleanup, docond, external). Selection drives the inspector panel.
36
+ - Read-only phase: no forms that mutate; every mutation UI comes later through
37
+ `/api/changes/*` with preview → apply.
38
+
39
+ ## Design quality (not a default template)
40
+
41
+ - Hierarchy on purpose: the chain graph and the job's execution attributes are the focus;
42
+ metadata recedes. Attributes grouped (identity, scheduling, execution, notifications,
43
+ resources, variables, ON/DO), not a 75-row flat table.
44
+ - Intentional hover/focus/selected states on nodes, edges and rows; keyboard navigation in
45
+ lists and graph (Tab to nodes, Enter opens, Esc closes the inspector).
46
+ - Both light and dark themes read as finished; colour is never the only carrier of meaning
47
+ (external links and findings also get an icon or label).
48
+ - Empty, loading and error states designed for every query; no spinner-only screens.
49
+
50
+ ## Tests (TDD)
51
+
52
+ - Vitest + React Testing Library + `@testing-library/user-event` (`userEvent.setup()` once per
53
+ test, always `await`); MSW for `/api/*` with handlers built from fixture JSON, never mocking
54
+ TanStack Query or React internals.
55
+ - Query by role, then label, then text; `data-testid` only for the graph canvas.
56
+ - `findBy*`/`waitFor` for async, never timers; no snapshot tests of components.
57
+ - Accessibility: `vitest-axe` on every page component; no violations.
58
+ - Playwright smoke (`test:e2e`): build, start `ctmchain serve` on a fixture repo, open the
59
+ folder list, open one folder graph, open one job, see the validate page. Runs in CI on
60
+ Linux only.
61
+ - Coverage ≥ 80% for `features/` and `lib/`; `components/ui` excluded.
62
+
63
+ ## Verify
64
+
65
+ 1. `npm run lint && npm run typecheck && npm test -- --run --coverage && npm run build`.
66
+ 2. `npm run gen:api` produces no diff (types in sync with the API snapshot).
67
+ 3. Checklist: tests written first · no `any`, no `console.log` · no hand-written API types ·
68
+ roles/labels queryable · axe clean · empty/loading/error states present · keyboard works ·
69
+ both themes checked · bundle report has no unexpected large chunk · no real data in
70
+ fixtures or MSW handlers.
71
+ 4. Finish with the `verify` skill and paste its report in the PR.
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: verify
3
+ description: End-of-part quality gate for controlm-chain-admin. Runs lint, types, tests with coverage, the no-real-data scan and a diff review, then writes a PASS/FAIL report. Use at the end of every backlog story, before opening a PR, after a refactor, or whenever someone asks to «verificar», «validar», «está ok?», «run the gate» or «check before PR».
4
+ ---
5
+
6
+ # verify — the common gate
7
+
8
+ Adapted from Everything Claude Code `verification-loop` (MIT, see `.claude/ATTRIBUTION.md`).
9
+ Every area skill (`python-core-tdd`, `fastapi-api`, `react-frontend`, `oss-repo-standards`)
10
+ ends by invoking this one. The report goes into the PR description.
11
+
12
+ ## 1. Run the script
13
+
14
+ ```bash
15
+ .claude/skills/verify/verify.sh # whole repo
16
+ .claude/skills/verify/verify.sh --python # only the Python gate
17
+ .claude/skills/verify/verify.sh --web # only the frontend gate
18
+ ```
19
+
20
+ The script detects what exists (`pyproject.toml`, `web/package.json`) and runs, in order:
21
+
22
+ | Phase | Python | Frontend |
23
+ |---|---|---|
24
+ | Lint | `ruff check .` and `ruff format --check .` | `npm run lint` |
25
+ | Types | `mypy src` | `npm run typecheck` |
26
+ | Tests | `pytest --cov=controlm_chain_admin --cov-fail-under=<gate>` | `npm test -- --run --coverage` |
27
+ | Build | `python -m build` (when `build` is installed) | `npm run build` |
28
+ | No real data | `git ls-files` grepped with the patterns in `.claude/no-real-data.patterns` (local, git-ignored) | same |
29
+ | Debug leftovers | `breakpoint()`, `pdb` in `src/` | `console.log` in `web/src/` |
30
+ | Diff | `git diff --stat` against the base branch | same |
31
+
32
+ A phase that fails stops the gate with `FAIL`; fix it before continuing. The no-real-data
33
+ patterns file is deliberately not in the repository; when it is missing the phase reports
34
+ `SKIPPED (no patterns file)` and the maintainer must run the gate locally before merging.
35
+
36
+ ## 2. Review the diff by hand
37
+
38
+ After the script passes, read `git diff <base>...HEAD` and answer, per file:
39
+
40
+ - Is every change intended and within the story's scope?
41
+ - Does each new behaviour have a test that was written first (test file in the same commit)?
42
+ - Are errors handled explicitly, with typed errors from `core`, never swallowed?
43
+ - Is anything duplicated that `core` already provides?
44
+ - Does any string look like real data (job names with a real application prefix, hostnames,
45
+ user names, e-mail addresses, internal URLs)?
46
+
47
+ ## 3. Write the report
48
+
49
+ ```text
50
+ VERIFICATION REPORT — <story id> — <date>
51
+ Lint: PASS/FAIL
52
+ Types: PASS/FAIL (n errors)
53
+ Tests: PASS/FAIL (x/y passed, z% coverage, gate g%)
54
+ Build: PASS/FAIL/SKIPPED
55
+ No real data: PASS/FAIL/SKIPPED
56
+ Debug left: PASS/FAIL
57
+ Diff: n files, +a/−b, reviewed by hand: yes/no
58
+ Overall: READY / NOT READY for PR
59
+ Issues:
60
+ 1. ...
61
+ ```
62
+
63
+ `READY` requires every phase `PASS` (or `SKIPPED` only for Build and, locally run later, No
64
+ real data) and the hand review done. Never report `READY` from memory: paste the script output.
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bash
2
+ # verify.sh — the controlm-chain-admin quality gate. Prints a PASS/FAIL report, exits 1 on FAIL.
3
+ # Usage: .claude/skills/verify/verify.sh [--python] [--web] [--base <git-ref>]
4
+ set -uo pipefail
5
+
6
+ ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel 2>/dev/null || pwd)"
7
+ cd "$ROOT"
8
+ RUN_PY=1; RUN_WEB=1; BASE="origin/main"
9
+ while [ $# -gt 0 ]; do
10
+ case "$1" in
11
+ --python) RUN_WEB=0 ;;
12
+ --web) RUN_PY=0 ;;
13
+ --base) BASE="$2"; shift ;;
14
+ *) echo "unknown option: $1" >&2; exit 2 ;;
15
+ esac
16
+ shift
17
+ done
18
+
19
+ declare -a REPORT=(); FAIL=0
20
+ record() { REPORT+=("$(printf '%-14s %s' "$1:" "$2")"); case "$2" in FAIL*) FAIL=1 ;; esac; }
21
+ run() { # run <label> <command...>; keeps the last 25 lines of output on failure
22
+ local label="$1"; shift
23
+ local out; out="$("$@" 2>&1)"; local rc=$?
24
+ if [ $rc -eq 0 ]; then record "$label" "PASS"; else record "$label" "FAIL (exit $rc)"; printf -- '--- %s\n%s\n' "$label" "$(printf '%s\n' "$out" | tail -25)"; fi
25
+ return $rc
26
+ }
27
+
28
+ # ---------------------------------------------------------------- Python
29
+ if [ $RUN_PY -eq 1 ] && [ -f pyproject.toml ]; then
30
+ run "Lint (ruff)" ruff check . && run "Format (ruff)" ruff format --check . || true
31
+ [ -d src ] && run "Types (mypy)" mypy src || true
32
+ GATE="$(sed -n 's/^fail_under *= *\([0-9]*\).*/\1/p' pyproject.toml | head -1)"; GATE="${GATE:-90}"
33
+ run "Tests (pytest)" pytest -q --cov=controlm_chain_admin --cov-report=term-missing --cov-fail-under="$GATE" || true
34
+ if python3 -c "import build" 2>/dev/null; then run "Build (wheel)" python3 -m build --outdir /tmp/ctmchain-build-check || true; else record "Build (wheel)" "SKIPPED (pip install build)"; fi
35
+ if [ -d src ] && grep -rnE "breakpoint\(\)|import pdb|pdb\.set_trace" src >/dev/null 2>&1; then record "Debug left (py)" "FAIL"; grep -rnE "breakpoint\(\)|import pdb|pdb\.set_trace" src; else record "Debug left (py)" "PASS"; fi
36
+ elif [ $RUN_PY -eq 1 ]; then
37
+ record "Python" "SKIPPED (no pyproject.toml)"
38
+ fi
39
+
40
+ # ---------------------------------------------------------------- Frontend
41
+ if [ $RUN_WEB -eq 1 ] && [ -f web/package.json ]; then
42
+ if [ ! -d web/node_modules ]; then
43
+ record "Frontend" "SKIPPED (web/node_modules missing: run npm ci in web/)"
44
+ else
45
+ run "Lint (web)" npm --prefix web run --silent lint || true
46
+ run "Types (web)" npm --prefix web run --silent typecheck || true
47
+ run "Tests (web)" npm --prefix web run --silent test:run -- --coverage || true
48
+ run "Build (web)" npm --prefix web run --silent build || true
49
+ fi
50
+ if grep -rn "console.log" web/src >/dev/null 2>&1; then record "Debug left (web)" "FAIL"; grep -rn "console.log" web/src | head; else record "Debug left (web)" "PASS"; fi
51
+ elif [ $RUN_WEB -eq 1 ]; then
52
+ record "Frontend" "SKIPPED (no web/package.json)"
53
+ fi
54
+
55
+ # ---------------------------------------------------------------- No real data
56
+ PATTERNS=".claude/no-real-data.patterns"
57
+ if [ -f "$PATTERNS" ]; then
58
+ HITS="$(git ls-files -z | xargs -0 grep -nIiE -f "$PATTERNS" -- 2>/dev/null | grep -v "^${PATTERNS}:" || true)"
59
+ if [ -n "$HITS" ]; then record "No real data" "FAIL ($(printf '%s\n' "$HITS" | wc -l | tr -d ' ') hits)"; printf '%s\n' "$HITS" | head -20; else record "No real data" "PASS"; fi
60
+ else
61
+ record "No real data" "SKIPPED (no $PATTERNS; run locally before merging)"
62
+ fi
63
+
64
+ # ---------------------------------------------------------------- Diff
65
+ if git rev-parse --verify -q "$BASE" >/dev/null; then
66
+ record "Diff vs $BASE" "$(git diff --shortstat "$BASE"...HEAD 2>/dev/null | sed 's/^ *//' || echo 'n/a')"
67
+ else
68
+ record "Diff" "base $BASE not found (use --base)"
69
+ fi
70
+
71
+ echo; echo "VERIFICATION REPORT — $(date +%Y-%m-%d) — $(git rev-parse --short HEAD 2>/dev/null || echo 'no commits')"
72
+ printf '%s\n' "${REPORT[@]}"
73
+ if [ $FAIL -eq 1 ]; then echo "Overall: NOT READY"; exit 1; else echo "Overall: READY (hand review of the diff still required)"; fi