workflow-loop 0.3.8__tar.gz → 0.3.9__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 (127) hide show
  1. {workflow_loop-0.3.8/src/workflow_loop.egg-info → workflow_loop-0.3.9}/PKG-INFO +9 -9
  2. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/README.md +8 -8
  3. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/pyproject.toml +1 -1
  4. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/__init__.py +2 -2
  5. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/artifact_validation.py +46 -3
  6. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/bug_record.py +59 -15
  7. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/cli.py +186 -38
  8. workflow_loop-0.3.9/src/workflow_loop/code_symbols.py +145 -0
  9. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/code_design/update_code_design.md +9 -1
  10. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/qa/test.md +3 -1
  11. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/qa/test_code.md +1 -1
  12. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/qa/test_code_implementation.md +1 -1
  13. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/qa/test_plan.md +1 -1
  14. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/reproduce/reproduce.md +7 -3
  15. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/code_design/code_design.md +2 -0
  16. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/reproduce/reproduce.md +8 -1
  17. workflow_loop-0.3.9/src/workflow_loop/design_sync.py +209 -0
  18. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/journal.py +20 -0
  19. workflow_loop-0.3.9/src/workflow_loop/machine_collect.py +641 -0
  20. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/markdown_links.py +176 -40
  21. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/records.py +924 -120
  22. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/rollback.py +84 -7
  23. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/stages/stages.py +41 -1
  24. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/state.py +5 -0
  25. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/test_execution.py +14 -2
  26. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/test_mapping.py +29 -0
  27. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/test_runner.py +48 -0
  28. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/topic.py +6 -8
  29. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/traceability.py +76 -3
  30. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/verification.py +2 -2
  31. {workflow_loop-0.3.8 → workflow_loop-0.3.9/src/workflow_loop.egg-info}/PKG-INFO +9 -9
  32. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop.egg-info/SOURCES.txt +16 -1
  33. workflow_loop-0.3.9/tests/test_design_sync_tables.py +215 -0
  34. workflow_loop-0.3.9/tests/test_empty_result_table_guard.py +71 -0
  35. workflow_loop-0.3.9/tests/test_gate_self_heal_output.py +224 -0
  36. workflow_loop-0.3.9/tests/test_git_baseline_exit.py +171 -0
  37. workflow_loop-0.3.9/tests/test_machine_collect.py +437 -0
  38. workflow_loop-0.3.9/tests/test_machine_collect_extension.py +234 -0
  39. workflow_loop-0.3.9/tests/test_multibug_workflow.py +269 -0
  40. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_records.py +24 -10
  41. workflow_loop-0.3.9/tests/test_recovery_journal_boundary.py +136 -0
  42. workflow_loop-0.3.9/tests/test_registration_guidance.py +164 -0
  43. workflow_loop-0.3.9/tests/test_regression_skip.py +189 -0
  44. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_rollback.py +2 -1
  45. workflow_loop-0.3.9/tests/test_version_document_sources.py +70 -0
  46. workflow_loop-0.3.9/tests/test_workflow_guidance.py +588 -0
  47. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/LICENSE +0 -0
  48. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/setup.cfg +0 -0
  49. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/acceptance_records.py +0 -0
  50. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/artifact_paths.py +0 -0
  51. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/acceptance/acceptance.md +0 -0
  52. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/acceptance/acceptance_plan.md +0 -0
  53. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/code_design/code_design.md +0 -0
  54. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/code_design/project_design_init.md +0 -0
  55. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/global/document_writing.md +0 -0
  56. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/global/workflow_lifecycle.md +0 -0
  57. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/impl/code_implementation.md +0 -0
  58. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/impl/impl.md +0 -0
  59. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/spec/spec.md +0 -0
  60. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Standardized_Repository/spike/spike.md +0 -0
  61. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/acceptance/acceptance_plan.md +0 -0
  62. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/acceptance/acceptance_result.md +0 -0
  63. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/code_design/project_design_init_evidence.md +0 -0
  64. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/impl/impl.md +0 -0
  65. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/qa/test.md +0 -0
  66. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/qa/test_plan.md +0 -0
  67. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/spec/spec.md +0 -0
  68. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/data/Template_Repository/spike/spike.md +0 -0
  69. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/diagnostics.py +0 -0
  70. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/installer.py +0 -0
  71. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/path_composer.py +0 -0
  72. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/process_runner.py +0 -0
  73. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/project.py +0 -0
  74. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/role_doc.py +0 -0
  75. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/snapshots.py +0 -0
  76. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/spike_reuse.py +0 -0
  77. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/spike_validation.py +0 -0
  78. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/stage_materials.py +0 -0
  79. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/stages/__init__.py +0 -0
  80. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/stages/base.py +0 -0
  81. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/test_entry.py +0 -0
  82. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/test_report.py +0 -0
  83. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop/topic_relations.py +0 -0
  84. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop.egg-info/dependency_links.txt +0 -0
  85. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop.egg-info/entry_points.txt +0 -0
  86. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop.egg-info/requires.txt +0 -0
  87. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/src/workflow_loop.egg-info/top_level.txt +0 -0
  88. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_acceptance_records.py +0 -0
  89. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_architecture_validation.py +0 -0
  90. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_artifact_paths.py +0 -0
  91. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_bug_record.py +0 -0
  92. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_bug_validation.py +0 -0
  93. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_commands.py +0 -0
  94. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_current_workflow_contracts.py +0 -0
  95. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_current_workflow_qa.py +0 -0
  96. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_diagnostics.py +0 -0
  97. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_gate_plan_path_diagnostics.py +0 -0
  98. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_gate_rework_stability.py +0 -0
  99. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_installer.py +0 -0
  100. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_light_task.py +0 -0
  101. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_maintenance.py +0 -0
  102. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_maintenance_scripts.py +0 -0
  103. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_markdown_links.py +0 -0
  104. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_path_composer.py +0 -0
  105. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_process_runner.py +0 -0
  106. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_project.py +0 -0
  107. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_project_design_init.py +0 -0
  108. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_public_project.py +0 -0
  109. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_release_script.py +0 -0
  110. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_release_workflow.py +0 -0
  111. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_return_rework_flow.py +0 -0
  112. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_snapshots.py +0 -0
  113. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_spike_assets.py +0 -0
  114. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_spike_validation.py +0 -0
  115. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_stage_materials.py +0 -0
  116. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_stages.py +0 -0
  117. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_state.py +0 -0
  118. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_table_entry_registration.py +0 -0
  119. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_test_entry.py +0 -0
  120. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_test_execution.py +0 -0
  121. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_test_mapping.py +0 -0
  122. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_test_report.py +0 -0
  123. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_test_runner.py +0 -0
  124. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_topic_relations.py +0 -0
  125. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_traceability.py +0 -0
  126. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_verification.py +0 -0
  127. {workflow_loop-0.3.8 → workflow_loop-0.3.9}/tests/test_workflow_acceptance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workflow-loop
3
- Version: 0.3.8
3
+ Version: 0.3.9
4
4
  Summary: 为 AI 驱动的软件开发提供有状态、可验证、可回退的工作流管理。
5
5
  Author: yuzyf
6
6
  License-Expression: MIT
@@ -95,29 +95,29 @@ flowchart TD
95
95
  - 安装时能够访问 GitHub 和 PyPI(Python 公共软件包仓库)。
96
96
  - 执行安装命令前,先进入要由 Workflow Loop 管理的项目根目录。
97
97
 
98
- ## 安装 0.3.8
98
+ ## 安装 0.3.9
99
99
 
100
100
  安装器先进行只读检查并列出项目侧和电脑侧可能发生的全部持久修改。用户确认一次后,安装器才安装或复用全局 `workflow` 命令,并把智能体契约、产物模板和工作规范写入当前项目;用户取消或安装失败时不会留下只完成一部分的安装。
101
101
 
102
102
  ### macOS
103
103
 
104
104
  ```bash
105
- curl -fsSL https://github.com/yuzyf/workflow_loop/releases/download/v0.3.8/install.sh | bash
105
+ curl -fsSL https://github.com/yuzyf/workflow_loop/releases/download/v0.3.9/install.sh | bash
106
106
  ```
107
107
 
108
108
  ### Linux
109
109
 
110
110
  ```bash
111
- curl -fsSL https://github.com/yuzyf/workflow_loop/releases/download/v0.3.8/install.sh | bash
111
+ curl -fsSL https://github.com/yuzyf/workflow_loop/releases/download/v0.3.9/install.sh | bash
112
112
  ```
113
113
 
114
114
  ### 原生 Windows
115
115
 
116
116
  ```powershell
117
- powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://github.com/yuzyf/workflow_loop/releases/download/v0.3.8/install.ps1 | iex"
117
+ powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://github.com/yuzyf/workflow_loop/releases/download/v0.3.9/install.ps1 | iex"
118
118
  ```
119
119
 
120
- 安装命令固定读取 `v0.3.8` 正式发布中的脚本;不会跟随内容可能变化的 `latest`(最新版本)地址。
120
+ 安装命令固定读取 `v0.3.9` 正式发布中的脚本;不会跟随内容可能变化的 `latest`(最新版本)地址。
121
121
 
122
122
  ## 更新与卸载
123
123
 
@@ -125,7 +125,7 @@ powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://github.com/y
125
125
 
126
126
  ```bash
127
127
  workflow update
128
- workflow update --version 0.3.8
128
+ workflow update --version 0.3.9
129
129
  ```
130
130
 
131
131
  更新按需补齐电脑全局命令和当前项目,只直接覆盖项目根 `AGENTS.md`、`.workflow_loop/Template_Repository/`、`.workflow_loop/Standardized_Repository/`,以及 `.workflow_loop/project.json` 中的安装版本字段。更新不创建备份,不回滚已经完成的步骤;当前轮次状态、历史、回退资料、业务代码和正式产物保持不变。失败后重新执行同一命令即可继续补齐。
@@ -229,10 +229,10 @@ uv run python -m build
229
229
 
230
230
  ## 发布正式版本
231
231
 
232
- 项目维护者确认当前仓库内容可以直接发布后,在仓库根目录执行下面的命令,并把 `0.3.8` 替换成要发布的新版本号:
232
+ 项目维护者确认当前仓库内容可以直接发布后,在仓库根目录执行下面的命令,并把 `0.3.9` 替换成要发布的新版本号:
233
233
 
234
234
  ```bash
235
- uv run python scripts/release.py 0.3.8
235
+ uv run python scripts/release.py 0.3.9
236
236
  ```
237
237
 
238
238
  运行这条命令本身就表示维护者接受当前仓库状态并承担跳过本地发布检查的风险。脚本不会再次确认,也不会在本地运行测试、构建或远程版本查询。它依次执行:
@@ -76,29 +76,29 @@ flowchart TD
76
76
  - 安装时能够访问 GitHub 和 PyPI(Python 公共软件包仓库)。
77
77
  - 执行安装命令前,先进入要由 Workflow Loop 管理的项目根目录。
78
78
 
79
- ## 安装 0.3.8
79
+ ## 安装 0.3.9
80
80
 
81
81
  安装器先进行只读检查并列出项目侧和电脑侧可能发生的全部持久修改。用户确认一次后,安装器才安装或复用全局 `workflow` 命令,并把智能体契约、产物模板和工作规范写入当前项目;用户取消或安装失败时不会留下只完成一部分的安装。
82
82
 
83
83
  ### macOS
84
84
 
85
85
  ```bash
86
- curl -fsSL https://github.com/yuzyf/workflow_loop/releases/download/v0.3.8/install.sh | bash
86
+ curl -fsSL https://github.com/yuzyf/workflow_loop/releases/download/v0.3.9/install.sh | bash
87
87
  ```
88
88
 
89
89
  ### Linux
90
90
 
91
91
  ```bash
92
- curl -fsSL https://github.com/yuzyf/workflow_loop/releases/download/v0.3.8/install.sh | bash
92
+ curl -fsSL https://github.com/yuzyf/workflow_loop/releases/download/v0.3.9/install.sh | bash
93
93
  ```
94
94
 
95
95
  ### 原生 Windows
96
96
 
97
97
  ```powershell
98
- powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://github.com/yuzyf/workflow_loop/releases/download/v0.3.8/install.ps1 | iex"
98
+ powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://github.com/yuzyf/workflow_loop/releases/download/v0.3.9/install.ps1 | iex"
99
99
  ```
100
100
 
101
- 安装命令固定读取 `v0.3.8` 正式发布中的脚本;不会跟随内容可能变化的 `latest`(最新版本)地址。
101
+ 安装命令固定读取 `v0.3.9` 正式发布中的脚本;不会跟随内容可能变化的 `latest`(最新版本)地址。
102
102
 
103
103
  ## 更新与卸载
104
104
 
@@ -106,7 +106,7 @@ powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://github.com/y
106
106
 
107
107
  ```bash
108
108
  workflow update
109
- workflow update --version 0.3.8
109
+ workflow update --version 0.3.9
110
110
  ```
111
111
 
112
112
  更新按需补齐电脑全局命令和当前项目,只直接覆盖项目根 `AGENTS.md`、`.workflow_loop/Template_Repository/`、`.workflow_loop/Standardized_Repository/`,以及 `.workflow_loop/project.json` 中的安装版本字段。更新不创建备份,不回滚已经完成的步骤;当前轮次状态、历史、回退资料、业务代码和正式产物保持不变。失败后重新执行同一命令即可继续补齐。
@@ -210,10 +210,10 @@ uv run python -m build
210
210
 
211
211
  ## 发布正式版本
212
212
 
213
- 项目维护者确认当前仓库内容可以直接发布后,在仓库根目录执行下面的命令,并把 `0.3.8` 替换成要发布的新版本号:
213
+ 项目维护者确认当前仓库内容可以直接发布后,在仓库根目录执行下面的命令,并把 `0.3.9` 替换成要发布的新版本号:
214
214
 
215
215
  ```bash
216
- uv run python scripts/release.py 0.3.8
216
+ uv run python scripts/release.py 0.3.9
217
217
  ```
218
218
 
219
219
  运行这条命令本身就表示维护者接受当前仓库状态并承担跳过本地发布检查的风险。脚本不会再次确认,也不会在本地运行测试、构建或远程版本查询。它依次执行:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "workflow-loop"
3
- version = "0.3.8"
3
+ version = "0.3.9"
4
4
  description = "为 AI 驱动的软件开发提供有状态、可验证、可回退的工作流管理。"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  # 包版本号,用于 pip/uv 安装时版本匹配
2
- __version__ = "0.3.8"
2
+ __version__ = "0.3.9"
3
3
  # 产品身份标识:workflow --version 输出、安装脚本身份核对和安装事务校验共用同一组常量
4
- # 本次发布版本为 0.3.8;后续发布使用尚未被 PyPI 占用的新版本号
4
+ # 本次发布版本为 0.3.9;后续发布使用尚未被 PyPI 占用的新版本号
5
5
  PRODUCT_NAME = "workflow-loop"
6
6
  PRODUCT_IDENTITY = f"{PRODUCT_NAME} {__version__}"
@@ -614,6 +614,10 @@ def _required_final_machine_record_ids(wf_state) -> tuple[set[str] | None, str]:
614
614
  required.update(record.test_record_ids)
615
615
 
616
616
  regression = wf_state.regression_test
617
+ if regression.status == "skipped-by-no-change":
618
+ # R9/R9a:无代码改动跳过的轮次没有机器执行记录;设计同步照常,
619
+ # 结论按真实差异为无需修改,不要求不存在的 REG 编号。
620
+ return required, ""
617
621
  if regression.status != "passed" or not regression.record_id:
618
622
  return None, "最终全量回归没有当前有效的机器记录编号"
619
623
  required.add(regression.record_id)
@@ -1263,6 +1267,8 @@ def validate_project_design_feature_consistency(project_root: str) -> tuple[bool
1263
1267
  def validate_final_code_design_document(
1264
1268
  project_root: str,
1265
1269
  workflow_id: str,
1270
+ *,
1271
+ candidate_content: str | None = None,
1266
1272
  ) -> tuple[bool, str]:
1267
1273
  """校验最终架构文档已经完成产品、功能、架构和真实代码映射。
1268
1274
 
@@ -1272,8 +1278,8 @@ def validate_final_code_design_document(
1272
1278
  relative_path = artifact_paths_mod.CODE_DESIGN_DOC
1273
1279
  full_path = os.path.join(project_root, relative_path)
1274
1280
  errors: list[str] = []
1275
- architecture_exists = os.path.isfile(full_path)
1276
- content = _read_text(project_root, relative_path) if architecture_exists else ""
1281
+ architecture_exists = candidate_content is not None or os.path.isfile(full_path)
1282
+ content = candidate_content if candidate_content is not None else (_read_text(project_root, relative_path) if architecture_exists else "")
1277
1283
  if not architecture_exists:
1278
1284
  errors.append(f"{relative_path} 不存在")
1279
1285
 
@@ -1438,7 +1444,9 @@ def validate_final_code_design_document(
1438
1444
  extra_ids = sorted(actual_record_ids - required_record_ids)
1439
1445
  errors.append(
1440
1446
  f"{relative_path} 第 9 章“核对依据”字段必须精确列出当前机器记录编号;"
1441
- f"缺少={missing_ids},额外或拼接错误={extra_ids}"
1447
+ f"当前缺少={missing_ids},不在当前有效集合中的编号={extra_ids}"
1448
+ "测试或最终全量回归重跑会使旧编号失效;额外编号也可能是拼写或拼接错误,"
1449
+ "请从当前工作流状态重新取得有效编号集合,不要沿用历史编号"
1442
1450
  )
1443
1451
 
1444
1452
  if errors:
@@ -1517,6 +1525,27 @@ def validate_reproduce_documents(
1517
1525
  ]
1518
1526
 
1519
1527
  topics: list[str] = []
1528
+ from . import records as records_mod
1529
+
1530
+ workflow = load_state(project_root)
1531
+ uses_tables = workflow is not None and records_mod.workflow_uses_tables(workflow, project_root)
1532
+ fact_tables = {}
1533
+ table_problems, tables = records_mod.bug_record_tables(
1534
+ project_root, workflow_id, list(workflow.topics) if uses_tables else None,
1535
+ )
1536
+ failures.extend(detail for _, detail in table_problems)
1537
+ for table_relative, table in tables:
1538
+ fact_tables[table["验收主题"]] = table
1539
+ failures.extend(
1540
+ f"{table_relative}:{detail}" for _category, detail in
1541
+ records_mod.validate_table("bug_record", table, project_root=project_root)
1542
+ )
1543
+ if uses_tables:
1544
+ changed_bug_docs = list(dict.fromkeys(changed_bug_docs + _current_workflow_bug_documents(project_root, workflow_id)))
1545
+ for table in fact_tables.values():
1546
+ expected = f"bug/缺陷_{records_mod.bug_file_key(project_root, table['验收主题'])}.md"
1547
+ if expected not in changed_bug_docs:
1548
+ failures.append(f"主题「{table['验收主题']}」缺少本轮正式缺陷记录 {expected}")
1520
1549
  for rel_path in changed_bug_docs:
1521
1550
  filename = os.path.basename(rel_path)
1522
1551
  if not BUG_FILENAME_RE.match(filename):
@@ -1547,6 +1576,15 @@ def validate_reproduce_documents(
1547
1576
  else:
1548
1577
  topics.append(topic or "")
1549
1578
 
1579
+ fact_table = fact_tables.get(topic)
1580
+ if uses_tables and fact_table is None:
1581
+ failures.append(f"{filename} 的主题「{topic}」缺少对应的缺陷记录工作记录表")
1582
+ if fact_table is not None and fact_table.get("表版本") == "3":
1583
+ for heading in required_sections:
1584
+ if _section(content, heading) is None:
1585
+ failures.append(f"{filename} 缺少“{heading}”章节")
1586
+ continue
1587
+
1550
1588
  for heading in required_sections:
1551
1589
  allow_none = heading.startswith("7.")
1552
1590
  section_text = _section(content, heading)
@@ -2646,6 +2684,11 @@ def validate_final_regression_state(
2646
2684
  return (False, "找不到当前工作流状态,不能确认最终全量回归")
2647
2685
  result = state.regression_test
2648
2686
  failures: list[str] = []
2687
+ if result.status == "skipped-by-no-change":
2688
+ # R9:无代码改动跳过的轮次按判定依据核对,不要求不存在的执行事实
2689
+ if not result.skip_reason or not result.skipped_at:
2690
+ return (False, "最终全量回归标记为无代码改动跳过,但缺少跳过依据或判定时间")
2691
+ return (True, f"最终全量回归按无代码改动跳过(依据已记录:{result.skipped_at})")
2649
2692
  if result.status == "unavailable":
2650
2693
  failures.append("最终全量回归明确失败:当前平台没有可执行的项目全量测试入口")
2651
2694
  elif result.status != "passed":
@@ -4,6 +4,10 @@ from __future__ import annotations
4
4
 
5
5
  import re
6
6
  from pathlib import Path
7
+ from urllib.parse import unquote
8
+
9
+ from markdown_it import MarkdownIt
10
+ from markdown_it.common.utils import unescapeAll
7
11
 
8
12
  from . import artifact_paths as artifact_paths_mod
9
13
  from .state import load_state
@@ -77,28 +81,68 @@ def _replace_result_update(content: str, stage_label: str, workflow_id: str, bod
77
81
  return content[: section_match.start(1)] + section + content[section_match.end(1) :]
78
82
 
79
83
 
84
+ def index_entry(content: str, filename: str) -> tuple[tuple[int, int], list[str]] | None:
85
+ """定位一个缺陷索引行,返回原文行范围和单元格;重复入口直接拒绝。"""
86
+ found = []
87
+ row_range = None
88
+ cells: list[str] = []
89
+ matches = False
90
+ for token in MarkdownIt("commonmark").enable("table").parse(content):
91
+ if token.type == "tr_open":
92
+ row_range, cells, matches = token.map, [], False
93
+ elif token.type == "inline" and row_range is not None:
94
+ if not cells:
95
+ matches = any(
96
+ child.type == "link_open"
97
+ and unquote(child.attrGet("href") or "") in {filename, f"./{filename}"}
98
+ for child in token.children or []
99
+ )
100
+ cells.append(unescapeAll(token.content))
101
+ elif token.type == "tr_close":
102
+ if matches:
103
+ if len(cells) < 2:
104
+ raise ValueError(f"缺陷索引中 {filename} 的条目缺少入口或状态列")
105
+ found.append((tuple(row_range), cells))
106
+ row_range = None
107
+ if len(found) > 1:
108
+ raise ValueError(f"缺陷索引中 {filename} 有重复入口,不能确定应更新哪一行")
109
+ return found[0] if found else None
110
+
111
+
112
+ def replace_index_entry(content: str, entry: tuple[int, int], cells: list[str]) -> str:
113
+ lines = content.splitlines(keepends=True)
114
+ rendered = [cell.replace("\\", "\\\\").replace("|", "\\|").replace("\n", "<br>") for cell in cells]
115
+ lines[entry[0]:entry[1]] = ["| " + " | ".join(rendered) + " |\n"]
116
+ return "".join(lines)
117
+
118
+
119
+ def index_width(content: str) -> int:
120
+ """旧索引可只有入口和状态两列;新增条目沿用其表格结构。"""
121
+ width = 0
122
+ for token in MarkdownIt("commonmark").enable("table").parse(content):
123
+ if token.type == "th_open":
124
+ width += 1
125
+ elif token.type == "thead_close":
126
+ if width not in {2, 4}:
127
+ raise ValueError("缺陷索引必须使用旧版两列或当前四列表格,不能覆盖未知表格结构")
128
+ return width
129
+ if content.strip():
130
+ raise ValueError("缺陷索引没有可解析的表格,保留原内容")
131
+ return 4
132
+
133
+
80
134
  def _update_index_status(project_root: str, filename: str, status: str) -> None:
81
135
  index_path = Path(project_root) / BUG_INDEX
82
136
  if not index_path.is_file():
83
137
  raise ValueError(f"{BUG_INDEX} 不存在,无法更新缺陷索引")
84
138
 
85
139
  content = index_path.read_text(encoding="utf-8")
86
- lines = content.splitlines()
87
- markers = {f"({filename})", f"(./{filename})"}
88
- found = False
89
- for index, line in enumerate(lines):
90
- if not any(marker in line for marker in markers) or not line.strip().startswith("|"):
91
- continue
92
- cells = [cell.strip() for cell in line.strip().strip("|").split("|")]
93
- if len(cells) < 2:
94
- continue
95
- cells[-1] = status
96
- lines[index] = "| " + " | ".join(cells) + " |"
97
- found = True
98
- break
99
- if not found:
140
+ entry = index_entry(content, filename)
141
+ if entry is None:
100
142
  raise ValueError(f"{BUG_INDEX} 没有链接缺陷记录: {filename}")
101
- index_path.write_text("\n".join(lines) + ("\n" if content.endswith("\n") else ""), encoding="utf-8")
143
+ row_range, cells = entry
144
+ cells[-1] = status
145
+ index_path.write_text(replace_index_entry(content, row_range, cells), encoding="utf-8")
102
146
 
103
147
 
104
148
  def update_status(