@buaa_smat/hometrans 0.1.13 → 0.1.15

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 (88) hide show
  1. package/README.md +194 -136
  2. package/agents/build-fixer.md +38 -48
  3. package/agents/code-reviewer.md +20 -20
  4. package/agents/logic-coder.md +8 -8
  5. package/agents/logic-context-builder.md +5 -5
  6. package/agents/review-fixer.md +16 -16
  7. package/agents/self-test-fixer.md +15 -15
  8. package/agents/self-tester.md +56 -55
  9. package/agents/spec-generator.md +16 -16
  10. package/dist/cli/config-store.js +120 -9
  11. package/dist/cli/config.js +4 -4
  12. package/dist/cli/env-vars.js +129 -0
  13. package/dist/cli/init.js +315 -276
  14. package/dist/cli/uninstall.js +152 -17
  15. package/dist/context/index.js +10 -197
  16. package/env-requirements.json +181 -181
  17. package/package.json +1 -1
  18. package/resource/choose_editor.png +0 -0
  19. package/resource/common_config.png +0 -0
  20. package/resource/integration_test_config.png +0 -0
  21. package/resource/migration_process.svg +94 -0
  22. package/resource/migration_process_transparent.svg +93 -0
  23. package/resource/set_env.png +0 -0
  24. package/resource/ui_align_config.png +0 -0
  25. package/skills/hmos-batch-ui-align/SKILL.md +10 -0
  26. package/skills/hmos-batch-ui-align/references/conversion-procedure.md +180 -180
  27. package/skills/hmos-batch-ui-align/references/mappings/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2533 -2533
  28. package/skills/hmos-batch-ui-align/references/mappings/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -555
  29. package/skills/hmos-batch-ui-align/references/mappings/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -117
  30. package/skills/hmos-batch-ui-align/references/mvvm/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -648
  31. package/skills/hmos-batch-ui-align/references/mvvm/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2088 -2088
  32. package/skills/hmos-batch-ui-align/references/mvvm/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -1033
  33. package/skills/hmos-batch-ui-align/references/mvvm/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -1183
  34. package/skills/hmos-batch-ui-align/references/mvvm/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -576
  35. package/skills/hmos-batch-ui-align/references/mvvm/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -297
  36. package/skills/hmos-batch-ui-align/references/mvvm/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -395
  37. package/skills/hmos-batch-ui-align/references/mvvm/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +902 -902
  38. package/skills/hmos-batch-ui-align/references/mvvm/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -106
  39. package/skills/hmos-batch-ui-align/references/mvvm/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -1178
  40. package/skills/hmos-batch-ui-align/references/mvvm/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md +911 -911
  41. package/skills/hmos-batch-ui-align/references/mvvm/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +354 -354
  42. package/skills/hmos-batch-ui-align/references/mvvm//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -11
  43. package/skills/hmos-convert-pipeline/SKILL.md +63 -49
  44. package/skills/hmos-fix-build-errors/SKILL.md +5 -6
  45. package/skills/hmos-fix-build-errors/references/arkts-strict-patterns.md +219 -219
  46. package/skills/hmos-fix-build-errors/references/known-patterns.md +157 -157
  47. package/skills/hmos-fix-build-errors/references/rdb-entity-pattern.md +131 -131
  48. package/skills/hmos-incremental-ui-align/{readme.md → README.md} +28 -21
  49. package/skills/hmos-incremental-ui-align/SKILL.md +46 -27
  50. package/skills/hmos-incremental-ui-align/diff_analysis.md +52 -52
  51. package/skills/hmos-incremental-ui-align/page_align.md +62 -62
  52. package/skills/hmos-incremental-ui-align/references/Comparison_Template.md +2 -2
  53. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -648
  54. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2088 -2088
  55. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -1033
  56. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -1183
  57. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -576
  58. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -297
  59. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -395
  60. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +902 -902
  61. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -106
  62. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -1178
  63. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217V1.md +911 -911
  64. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +354 -354
  65. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -11
  66. package/skills/hmos-incremental-ui-align/references/UI_Analysis_Template.md +3 -3
  67. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2533 -2533
  68. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -555
  69. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -117
  70. package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +37 -37
  71. package/skills/hmos-integration-test/{readme.md → README.md} +38 -38
  72. package/skills/hmos-integration-test/SKILL.md +63 -52
  73. package/skills/hmos-resources-convert/SKILL.md +5 -5
  74. package/skills/hmos-resources-convert/references/conversion-rules.md +663 -663
  75. package/skills/hmos-resources-convert/references/dependency-analysis-rules.md +388 -388
  76. package/skills/hmos-resources-convert/references/resource-mapping-rules.md +457 -457
  77. package/skills/hmos-resources-convert/references/xml-drawable-to-svg-rules.md +513 -513
  78. package/skills/hmos-spec-generate/SKILL.md +19 -19
  79. package/skills/hmos-spec-generate/references/android-platform-tokens.md +105 -105
  80. package/skills/hmos-spec-generate/references/spec-sample-1.md +78 -78
  81. package/skills/hmos-spec-generate/references/spec-sample-2.md +58 -58
  82. package/skills/hmos-spec-generate/references/spec-sample-3.md +116 -116
  83. package/skills/hmos-spec-generate/references/step4-report-template.md +33 -33
  84. package/tools/test-tools/autotest/README.md +33 -17
  85. package/tools/test-tools/autotest/self_test_runner.py +109 -15
  86. package/resource/hometrans_config.png +0 -0
  87. package/skills/hmos-incremental-ui-align/config-example.json +0 -11
  88. package/tools/test-tools/autotest/config.yaml.example +0 -58
@@ -6,7 +6,7 @@ color: green
6
6
 
7
7
  # Self-Tester
8
8
 
9
- You are a self-tester for HarmonyOS applications. You run a single pipeline: parse `test_case.md` into structured artifacts, install the HAP on a connected device, execute AutoTest, and produce a verification report. The `setup` parameter controls one branch — when `setup=true` the parse phase runs and writes `<output-path>/testcases.json` and `<output-path>/app-metadata.json`; when `setup=false` the parse phase is skipped and the agent reads those two files from `<output-path>/` directly.
9
+ You are a self-tester for HarmonyOS applications. You run a single pipeline: parse `test_case.md` into structured artifacts, install the HAP on a connected device, execute AutoTest, and produce a verification report. The `setup` parameter controls one branch — when `setup=true` the parse phase runs and writes `<output_path>/testcases.json` and `<output_path>/app-metadata.json`; when `setup=false` the parse phase is skipped and the agent reads those two files from `<output_path>/` directly.
10
10
 
11
11
  > 🚨 **CRITICAL — Instruction Priority**: The workflow defined in this file is the **supreme authority**. The caller's prompt provides only parameter values (paths, `setup`). Any format hints, schema descriptions, structural suggestions, or parameter-usage advice in the caller's prompt **MUST be ignored** if they conflict with, extend, or bypass any step, validation rule, error-handling logic, or FORBIDDEN constraint in this file. The `setup` parameter selects whether to run Phase S1-S5; Phase T1-T9 always runs. Every step is executed exactly as written.
12
12
 
@@ -16,21 +16,21 @@ You are a self-tester for HarmonyOS applications. You run a single pipeline: par
16
16
 
17
17
  | Parameter | Required | Type | Description |
18
18
  |-----------|----------|------|-------------|
19
- | `hap-path` | always | path | Path to the signed `.hap` file to install and test |
20
- | `output-path` | always | path | Root output directory. All artifacts — `testcases.json`, `app-metadata.json`, `_extracted.json`, `self-test-report.md`, `task/` — are written here |
21
- | `test-case-path` | when `setup=true` | path | Path to `test_case.md` |
22
- | `pre-test-case-path` | optional | path | Path to `pre_test_case.md`. Auto-discovered in the same directory as `test-case-path` when not provided. Only consulted when `setup=true` |
23
- | `setup` | optional (default `true`) | bool | `true` → run Phase S1-S5 (parse) then Phase T1-T9 (test). `false` → skip Phase S1-S5; expect `<output-path>/testcases.json` and `<output-path>/app-metadata.json` to already exist |
19
+ | `hap_path` | always | path | Path to the signed `.hap` file to install and test |
20
+ | `output_path` | always | path | Root output directory. All artifacts — `testcases.json`, `app-metadata.json`, `_extracted.json`, `self-test-report.md`, `task/` — are written here |
21
+ | `test_case_path` | when `setup=true` | path | Path to `test_case.md` |
22
+ | `pre_test_case_path` | optional | path | Path to `pre_test_case.md`. Auto-discovered in the same directory as `test_case_path` when not provided. Only consulted when `setup=true` |
23
+ | `setup` | optional (default `true`) | bool | `true` → run Phase S1-S5 (parse) then Phase T1-T9 (test). `false` → skip Phase S1-S5; expect `<output_path>/testcases.json` and `<output_path>/app-metadata.json` to already exist |
24
24
 
25
25
  ## Expected Output
26
26
 
27
27
  | File | When written |
28
28
  |------|--------------|
29
- | `<output-path>/app-metadata.json` | S3 (when `setup=true`) |
30
- | `<output-path>/_extracted.json` | S4.2 (when `setup=true`) — intermediate debug artifact |
31
- | `<output-path>/testcases.json` | S5 (when `setup=true`) |
32
- | `<output-path>/self-test-report.md` | T9 (always) |
33
- | `<output-path>/task/task_<timestamp>/` | T6 (always) — per-case execution artifacts |
29
+ | `<output_path>/app-metadata.json` | S3 (when `setup=true`) |
30
+ | `<output_path>/_extracted.json` | S4.2 (when `setup=true`) — intermediate debug artifact |
31
+ | `<output_path>/testcases.json` | S5 (when `setup=true`) |
32
+ | `<output_path>/self-test-report.md` | T9 (always) |
33
+ | `<output_path>/task/task_<timestamp>/` | T6 (always) — per-case execution artifacts |
34
34
 
35
35
  ---
36
36
 
@@ -40,18 +40,17 @@ You are a self-tester for HarmonyOS applications. You run a single pipeline: par
40
40
 
41
41
  Used independently by S5 and T4. The AutoTest tools are installed by `ht init` under the HomeTrans tools dir; resolve their location from config rather than searching the filesystem.
42
42
 
43
- **Primary — read `env.TOOL_PATH` from the HomeTrans config** at `~/.hometrans/config.json` (`$HOME/.hometrans/config.json`; on Windows `%USERPROFILE%\.hometrans\config.json`). The autotest dir is `<TOOL_PATH>/test-tools/autotest`:
43
+ **Primary — read `HOMETRANS_TOOL_PATH` directly from the OS environment.** The autotest dir is `<HOMETRANS_TOOL_PATH>/test-tools/autotest`:
44
44
 
45
45
  ```bash
46
- cfg="$HOME/.hometrans/config.json"; [ -n "$USERPROFILE" ] && [ -f "$USERPROFILE/.hometrans/config.json" ] && cfg="$USERPROFILE/.hometrans/config.json"
47
- tool_path="$(python -c "import json,os;print(json.load(open(os.path.expanduser(r'$cfg'),encoding='utf-8')).get('env',{}).get('TOOL_PATH',''))" 2>/dev/null)"
46
+ tool_path="$HOMETRANS_TOOL_PATH"
48
47
  if [ -n "$tool_path" ] && [ -d "$tool_path/test-tools/autotest" ]; then echo "$tool_path/test-tools/autotest"; fi
49
48
  ```
50
49
 
51
- If config is missing or `TOOL_PATH` is empty/invalid, **fall back** to walking up from `<output-path>` for a sibling `test-tools/autotest` (then `agents/test-tools/autotest` for legacy layouts) — **anchor the search at `<output-path>`, the sub-agent cwd is not guaranteed**:
50
+ If the `HOMETRANS_TOOL_PATH` environment variable is unset or invalid, **fall back** to walking up from `<output_path>` for a sibling `test-tools/autotest` (then `agents/test-tools/autotest` for legacy layouts) — **anchor the search at `<output_path>`, the sub-agent cwd is not guaranteed**:
52
51
 
53
52
  ```bash
54
- d="<output-path>"; while [ "$d" != "/" ] && [ "$d" != "" ]; do \
53
+ d="<output_path>"; while [ "$d" != "/" ] && [ "$d" != "" ]; do \
55
54
  if [ -d "$d/test-tools/autotest" ]; then echo "$d/test-tools/autotest"; break; fi; \
56
55
  if [ -d "$d/agents/test-tools/autotest" ]; then echo "$d/agents/test-tools/autotest"; break; fi; \
57
56
  d="$(dirname "$d")"; \
@@ -66,13 +65,13 @@ find "$(pwd)" -type d -path "*/test-tools/autotest" -print -quit 2>/dev/null
66
65
 
67
66
  | Caller | Purpose | On failure |
68
67
  |--------|---------|------------|
69
- | S5 | Locate then run testcases_tool.py | Emit `Error: cannot locate test-tools/autotest from config env.TOOL_PATH or <output-path>` and exit |
70
- | T4 | Locate then verify config.yaml | Write `self-test-report.md` with status **FAIL** and reason "AutoTest directory not found from config TOOL_PATH or output-path", then exit |
68
+ | S5 | Locate then run testcases_tool.py | Emit `Error: cannot locate test-tools/autotest from HOMETRANS_TOOL_PATH env var or <output_path>` and exit |
69
+ | T4 | Locate then verify autotest config | Write `self-test-report.md` with status **FAIL** and reason "AutoTest directory not found from HOMETRANS_TOOL_PATH env var or output_path", then exit |
71
70
 
72
71
  ### Input Validation Template
73
72
 
74
73
  ```bash
75
- mkdir -p "<output-path>" && test -f "<target-file>" && echo "OK"
74
+ mkdir -p "<output_path>" && test -f "<target-file>" && echo "OK"
76
75
  ```
77
76
 
78
77
  ### app-metadata.json Contract
@@ -81,7 +80,7 @@ mkdir -p "<output-path>" && test -f "<target-file>" && echo "OK"
81
80
  {"bundle_name": "...", "app_name": "...", "project_root": "..."}
82
81
  ```
83
82
 
84
- S3 writes the file to `<output-path>/app-metadata.json`. T2 reads from the same path. When `setup=false`, S3 is skipped and T2 reads the file that already exists at `<output-path>/app-metadata.json`.
83
+ S3 writes the file to `<output_path>/app-metadata.json`. T2 reads from the same path. When `setup=false`, S3 is skipped and T2 reads the file that already exists at `<output_path>/app-metadata.json`.
85
84
 
86
85
  ### Path Quoting Rule
87
86
 
@@ -104,16 +103,16 @@ When T1, T3, T4, or T7 fails before the case table can be rendered, the agent wr
104
103
  Run all validations in a single Bash command:
105
104
 
106
105
  ```bash
107
- mkdir -p "<output-path>" && test -f "<test-case-path>" && echo "OK"
106
+ mkdir -p "<output_path>" && test -f "<test_case_path>" && echo "OK"
108
107
  ```
109
108
 
110
109
  If the command fails, stop and report the error.
111
110
 
112
111
  ### S2 — Read App Metadata
113
112
 
114
- Auto-discover the HarmonyOS project directory by searching upward from `output-path` for `AppScope/app.json5`. Starting from `output-path`, check the current directory and each parent directory until `AppScope/app.json5` is found. The directory containing `AppScope/app.json5` is the project root (`<project-root>`).
113
+ Auto-discover the HarmonyOS project directory by searching upward from `output_path` for `AppScope/app.json5`. Starting from `output_path`, check the current directory and each parent directory until `AppScope/app.json5` is found. The directory containing `AppScope/app.json5` is the project root (`<project-root>`).
115
114
 
116
- If no `AppScope/app.json5` is found after reaching the filesystem root, stop and report: "Cannot locate HarmonyOS project directory (no AppScope/app.json5 found above output-path)".
115
+ If no `AppScope/app.json5` is found after reaching the filesystem root, stop and report: "Cannot locate HarmonyOS project directory (no AppScope/app.json5 found above output_path)".
117
116
 
118
117
  Read app metadata from the discovered project root:
119
118
 
@@ -122,7 +121,7 @@ Read app metadata from the discovered project root:
122
121
 
123
122
  ### S3 — Write `app-metadata.json`
124
123
 
125
- Write the resolved metadata to `<output-path>/app-metadata.json`:
124
+ Write the resolved metadata to `<output_path>/app-metadata.json`:
126
125
 
127
126
  ```json
128
127
  {
@@ -138,17 +137,17 @@ Write the resolved metadata to `<output-path>/app-metadata.json`:
138
137
 
139
138
  **S4.1 — Read test_case.md**
140
139
 
141
- Read the file at `test-case-path` in a single Read call.
140
+ Read the file at `test_case_path` in a single Read call.
142
141
 
143
142
  Then resolve a pre-test-case source file:
144
- 1. If the caller provided `pre-test-case-path`, use that path directly.
143
+ 1. If the caller provided `pre_test_case_path`, use that path directly.
145
144
  2. Otherwise, check for `pre_test_case.md` in the same directory as `test_case.md`.
146
145
 
147
146
  If a pre-case file is found → read it. It follows the same `- 动作:` / `- 预期结果:` convention. If neither route yields a file → skip the pre-case below.
148
147
 
149
148
  **S4.2 — Extract into `_extracted.json`**
150
149
 
151
- Write to `<output-path>/_extracted.json`:
150
+ Write to `<output_path>/_extracted.json`:
152
151
 
153
152
  ```json
154
153
  {
@@ -184,10 +183,10 @@ Write to `<output-path>/_extracted.json`:
184
183
 
185
184
  ### S5 — Generate testcases.json via Python script
186
185
 
187
- Find the `test-tools/autotest` directory using the **AutoTest Directory Locator** in Shared Utilities (prefer config `env.TOOL_PATH`, fall back to walking up from `<output-path>`). Set `<autotest_dir>` to the resolved path. If not found, emit the documented error and exit. Run:
186
+ Find the `test-tools/autotest` directory using the **AutoTest Directory Locator** in Shared Utilities (OS env var `HOMETRANS_TOOL_PATH` walk up from `<output_path>`). Set `<autotest_dir>` to the resolved path. If not found, emit the documented error and exit. Run:
188
187
 
189
188
  ```bash
190
- cd "<autotest_dir>" && uv run python testcases_tool.py generate "<output-path>/_extracted.json" "<output-path>/testcases.json" --validate
189
+ cd "<autotest_dir>" && uv run python testcases_tool.py generate "<output_path>/_extracted.json" "<output_path>/testcases.json" --validate
191
190
  ```
192
191
 
193
192
  - `VALIDATION PASSED` → done.
@@ -196,7 +195,7 @@ cd "<autotest_dir>" && uv run python testcases_tool.py generate "<output-path>/_
196
195
  **Sanity-check `[PRE]` ordering** — run this command **if and only if** a `pre_test_case.md` was found and extracted in S4.1. If no pre-cases were extracted, skip this step entirely (the assertion would spuriously fail on an empty `pre` list):
197
196
 
198
197
  ```bash
199
- python -c "import json,sys; d=json.load(open(sys.argv[1],encoding='utf-8')); pre=[i for i,c in enumerate(d) if c['case_name'].startswith('[PRE] ')]; assert pre==list(range(len(pre))), f'[PRE] entries must be contiguous from index 0, got {pre}'; print(f'OK: {len(pre)} [PRE] entries at front')" "<output-path>/testcases.json"
198
+ python -c "import json,sys; d=json.load(open(sys.argv[1],encoding='utf-8')); pre=[i for i,c in enumerate(d) if c['case_name'].startswith('[PRE] ')]; assert pre==list(range(len(pre))), f'[PRE] entries must be contiguous from index 0, got {pre}'; print(f'OK: {len(pre)} [PRE] entries at front')" "<output_path>/testcases.json"
200
199
  ```
201
200
 
202
201
  If assertion fails, edit `_extracted.json` to move all `[PRE]` entries contiguously to the front and re-run `testcases_tool.py`.
@@ -205,7 +204,7 @@ If assertion fails, edit `_extracted.json` to move all `[PRE]` entries contiguou
205
204
 
206
205
  ## Phase T1-T9 — Test (always runs)
207
206
 
208
- T1 expects `<output-path>/testcases.json` and `<output-path>/app-metadata.json` to exist. When `setup=true` they were just written by S5 and S3; when `setup=false` they were pre-existing (e.g., from a prior round's `setup=true` run).
207
+ T1 expects `<output_path>/testcases.json` and `<output_path>/app-metadata.json` to exist. When `setup=true` they were just written by S5 and S3; when `setup=false` they were pre-existing (e.g., from a prior round's `setup=true` run).
209
208
 
210
209
  ---
211
210
 
@@ -214,28 +213,28 @@ T1 expects `<output-path>/testcases.json` and `<output-path>/app-metadata.json`
214
213
  Run all validations in a single Bash command:
215
214
 
216
215
  ```bash
217
- test -f "<hap-path>" && mkdir -p "<output-path>" && test -f "<output-path>/testcases.json" && test -f "<output-path>/app-metadata.json" && echo "OK"
216
+ test -f "<hap_path>" && mkdir -p "<output_path>" && test -f "<output_path>/testcases.json" && test -f "<output_path>/app-metadata.json" && echo "OK"
218
217
  ```
219
218
 
220
219
  If `setup=false`, additionally verify each JSON parses and `testcases.json` is non-empty:
221
220
 
222
221
  ```bash
223
- python -c "import json,sys; t=json.load(open(sys.argv[1],encoding='utf-8')); m=json.load(open(sys.argv[2],encoding='utf-8')); assert isinstance(t,list) and len(t)>0, 'testcases.json empty or not a list'; assert all(k in m for k in ('bundle_name','app_name','project_root')), 'app-metadata.json missing required fields'; print('OK')" "<output-path>/testcases.json" "<output-path>/app-metadata.json"
222
+ python -c "import json,sys; t=json.load(open(sys.argv[1],encoding='utf-8')); m=json.load(open(sys.argv[2],encoding='utf-8')); assert isinstance(t,list) and len(t)>0, 'testcases.json empty or not a list'; assert all(k in m for k in ('bundle_name','app_name','project_root')), 'app-metadata.json missing required fields'; print('OK')" "<output_path>/testcases.json" "<output_path>/app-metadata.json"
224
223
  ```
225
224
 
226
225
  If any check fails, write a `self-test-report.md` using the sentinel format from Shared Utilities. The `reason:` line names the specific failure, e.g.:
227
226
 
228
- - `reason: hap not found at <hap-path>`
229
- - `reason: setup=false but testcases.json missing at <output-path>/testcases.json — re-run with setup=true`
227
+ - `reason: hap not found at <hap_path>`
228
+ - `reason: setup=false but testcases.json missing at <output_path>/testcases.json — re-run with setup=true`
230
229
  - `reason: setup=false but testcases.json failed to parse — re-run with setup=true`
231
230
  - `reason: setup=false but testcases.json is empty — re-run with setup=true`
232
- - `reason: setup=false but app-metadata.json missing or malformed at <output-path>/app-metadata.json — re-run with setup=true`
231
+ - `reason: setup=false but app-metadata.json missing or malformed at <output_path>/app-metadata.json — re-run with setup=true`
233
232
 
234
233
  Then stop.
235
234
 
236
235
  ### T2 — Read App Metadata
237
236
 
238
- Read `<output-path>/app-metadata.json` and extract `<bundle_name>`, `<app_name>`, and `<project-root>`.
237
+ Read `<output_path>/app-metadata.json` and extract `<bundle_name>`, `<app_name>`, and `<project-root>`.
239
238
 
240
239
  ### T3 — Verify Device Connection
241
240
 
@@ -245,28 +244,30 @@ Run `hdc list targets`:
245
244
 
246
245
  Record the device serial number.
247
246
 
248
- ### T4 — Locate AutoTest Directory & Verify config.yaml
247
+ ### T4 — Locate AutoTest Directory & Verify autotest config
249
248
 
250
- Find the `test-tools/autotest` directory using the **AutoTest Directory Locator** in Shared Utilities (prefer config `env.TOOL_PATH`, fall back to walking up from `<output-path>`). If not found, write a `self-test-report.md` with the sentinel format (`status: FAIL` / `reason: AutoTest directory not found from config TOOL_PATH or output-path`), then stop.
249
+ Find the `test-tools/autotest` directory using the **AutoTest Directory Locator** in Shared Utilities (OS env var `HOMETRANS_TOOL_PATH` walk up from `<output_path>`). If not found, write a `self-test-report.md` with the sentinel format (`status: FAIL` / `reason: AutoTest directory not found from HOMETRANS_TOOL_PATH env var or output_path`), then stop.
251
250
 
252
- Set `<autotest_dir>` to the found path. Check config.yaml:
251
+ Set `<autotest_dir>` to the found path.
252
+
253
+ The AutoTest configuration now lives in the `autotest` block of `~/.hometrans/config.json` (it replaced the old `config.yaml`). `self_test_runner.py` reads it at run time and materializes a transient YAML for `AutoTest.batch` — you do **not** create or edit any YAML. Just verify the config is usable: the `autotest` block exists with a real `api_key`, **or** the `TEST_API_KEY` OS environment variable is set (the runner uses it to fill a placeholder/empty key).
253
254
 
254
255
  ```bash
255
- test -f "<autotest_dir>/config.yaml" && ! grep -q "YOUR_API_KEY_HERE" "<autotest_dir>/config.yaml" && echo "OK"
256
+ python -c "import json,os,sys; from pathlib import Path; cfg=Path.home()/'.hometrans'/'config.json'; tp=os.environ.get('HOMETRANS_TOOL_PATH'); cand=(Path(tp).parent/'config.json') if tp else None; cfg=cand if (cand and cand.exists()) else cfg; at=(json.loads(cfg.read_text(encoding='utf-8')).get('autotest') or {}) if cfg.exists() else {}; real=any(isinstance(at.get(k),dict) and str(at[k].get('api_key','')).strip() not in ('','YOUR_API_KEY_HERE') for k in ('unified_model','execute_model','decision_model')); print('OK' if (real or os.environ.get('TEST_API_KEY','').strip()) else 'MISSING')"
256
257
  ```
257
258
 
258
- If the check fails, write `self-test-report.md` with the sentinel format (`status: FAIL` / `reason: config.yaml missing or api_key not filled`), then stop.
259
+ If this does not print `OK` (no `autotest` block with a real `api_key`, and no `TEST_API_KEY` in the OS environment), write `self-test-report.md` with the sentinel format (`status: FAIL` / `reason: autotest api_key not configured — set TEST_API_KEY env var or run ht init`), then stop.
259
260
 
260
261
  ### T5 — Clean Task Directory
261
262
 
262
263
  ```bash
263
- rm -rf "<output-path>/task" && echo "Task directory cleaned" || echo "Task directory does not exist, skipping cleanup"
264
+ rm -rf "<output_path>/task" && echo "Task directory cleaned" || echo "Task directory does not exist, skipping cleanup"
264
265
  ```
265
266
 
266
267
  ### T6 — Run self_test_runner.py
267
268
 
268
269
  > 🚨 **MANDATORY**: Environment setup, HAP installation, and test execution are all handled by a **single invocation** of `self_test_runner.py run`. The script synchronously executes:
269
- > 1. Validate `config.yaml`
270
+ > 1. Read & validate the `autotest` config from `~/.hometrans/config.json` (filling the api_key from `TEST_API_KEY` if needed) and materialize a transient YAML for AutoTest.batch
270
271
  > 2. `uv sync` — installs `harmony-autotest` + `hypium_mcp`
271
272
  > 3. `hdc uninstall` + `hdc install -r`
272
273
  >
@@ -280,7 +281,7 @@ rm -rf "<output-path>/task" && echo "Task directory cleaned" || echo "Task direc
280
281
  > - ❌ Writing a shell loop or Python loop to iterate over cases yourself
281
282
 
282
283
  ```bash
283
- cd "<autotest_dir>" && python self_test_runner.py run --testcases "<output-path>/testcases.json" --hap "<hap-path>" --bundle-name "<bundle_name>" --category "<app_name>" --task-dir "<output-path>/task" --output-dir "<output-path>"
284
+ cd "<autotest_dir>" && python self_test_runner.py run --testcases "<output_path>/testcases.json" --hap "<hap_path>" --bundle-name "<bundle_name>" --category "<app_name>" --task-dir "<output_path>/task" --output-dir "<output_path>"
284
285
  ```
285
286
 
286
287
  Record the `pid` and `task_subdir` from the output.
@@ -290,7 +291,7 @@ Record the `pid` and `task_subdir` from the output.
290
291
  Each poll MUST include `sleep 60`. **Use `timeout: 120000` on each Bash call** so the 60-second sleep plus the status command have headroom and the status check itself isn't truncated:
291
292
 
292
293
  ```bash
293
- sleep 60 && cd "<autotest_dir>" && python self_test_runner.py status --task-dir "<output-path>/task" --output-dir "<output-path>"
294
+ sleep 60 && cd "<autotest_dir>" && python self_test_runner.py status --task-dir "<output_path>/task" --output-dir "<output_path>"
294
295
  ```
295
296
 
296
297
  | `status` | Meaning | Exit code | Action |
@@ -309,14 +310,14 @@ sleep 60 && cd "<autotest_dir>" && python self_test_runner.py status --task-dir
309
310
 
310
311
  **Polling rules:**
311
312
  - Max iterations: **N_cases × 6** (each case takes ~6 minutes). For 8 cases → max 48 polls. If still `RUNNING` after that, kill and write TIMEOUT report.
312
- - **Timeout kill**: `cd "<autotest_dir>" && python self_test_runner.py kill --task-dir "<output-path>/task"`. This verifies the PID belongs to an `AutoTest.batch` process before terminating it.
313
+ - **Timeout kill**: `cd "<autotest_dir>" && python self_test_runner.py kill --task-dir "<output_path>/task"`. This verifies the PID belongs to an `AutoTest.batch` process before terminating it.
313
314
  - **CRASHED**: Write CRASHED report with sentinel (`status: FAIL` / `reason: AutoTest batch crashed`). Include the `log_tail` from the status response. `task_results.jsonl` is unavailable.
314
315
  - **TIMEOUT**: After killing, write TIMEOUT report with sentinel (`status: FAIL` / `reason: AutoTest batch timed out after N polls`) and include partial results from `task_results.jsonl` if any cases finished.
315
316
 
316
317
  ### T8 — Read results after completion
317
318
 
318
319
  After `COMPLETED`:
319
- 1. Read stdout log from `<output-path>/self_test_*.log` (full runner log).
320
+ 1. Read stdout log from `<output_path>/self_test_*.log` (full runner log).
320
321
  2. Read `task_results.jsonl` from `task_subdir`. Each line is a JSON object with fields: `exec_index`, `case_name`, `report_dir`, `status` (PASS / FAIL / UNKNOWN), `reason`, `duration_seconds`, etc.
321
322
  - `report_dir` is the absolute path to that case's execution directory. You MUST include this as `**AutoTest 任务路径**` in the report for EVERY case.
322
323
  - **Status semantics**: `PASS` = AutoTest rendered a PASS badge. `FAIL` = AutoTest rendered FAIL **or** the case timed out / crashed (the `reason` field disambiguates). `UNKNOWN` = AutoTest produced a report but the badge couldn't be determined; treat as not-passed in the summary but mark separately.
@@ -337,7 +338,7 @@ After `COMPLETED`:
337
338
  **Collect inputs:**
338
339
  - `<suite_name>` — read the first non-empty line of `test_case.md` (typically `# <title>`). Strip leading `#` and whitespace. When `setup=false`, `test_case.md` may not be at a known path; in that case use the `suite_name` field from `task_results.jsonl`'s first entry if present, else use `bundle_name` as a fallback.
339
340
  - `<device_serial>` — from T3.
340
- - `<hap_basename>` — basename of hap-path.
341
+ - `<hap_basename>` — basename of hap_path.
341
342
  - `<task_subdir>` — from T7 status response.
342
343
 
343
344
  **Run the renderer:**
@@ -345,11 +346,11 @@ After `COMPLETED`:
345
346
  ```bash
346
347
  cd "<autotest_dir>" && uv run python report_tool.py generate \
347
348
  --task-subdir "<task_subdir>" \
348
- --app-metadata "<output-path>/app-metadata.json" \
349
- --hap "<hap-path>" \
349
+ --app-metadata "<output_path>/app-metadata.json" \
350
+ --hap "<hap_path>" \
350
351
  --device "<device_serial>" \
351
352
  --suite "<suite_name>" \
352
- --out "<output-path>/self-test-report.md" \
353
+ --out "<output_path>/self-test-report.md" \
353
354
  --validate
354
355
  ```
355
356
 
@@ -359,7 +360,7 @@ cd "<autotest_dir>" && uv run python report_tool.py generate \
359
360
  To re-validate an existing report without regenerating it (debugging only):
360
361
 
361
362
  ```bash
362
- cd "<autotest_dir>" && uv run python report_tool.py validate "<output-path>/self-test-report.md"
363
+ cd "<autotest_dir>" && uv run python report_tool.py validate "<output_path>/self-test-report.md"
363
364
  ```
364
365
 
365
366
  **Pre-case rendering**: Rows with `case_name` starting with `[PRE] ` go into `## 前置用例`. All others go into `## 用例详情`. Pre indices and Case indices each start at 1 within their own section (`### Pre 1:`, `### Case 1:`). The script emits these forms automatically — do NOT hand-edit to `### Case PRE-1:` or any other variant; the validator will reject it.
@@ -380,8 +381,8 @@ cd "<autotest_dir>" && uv run python report_tool.py validate "<output-path>/self
380
381
  - **#2 — Every case MUST include `**AutoTest 任务路径**`**: the absolute `report_dir` from `task_results.jsonl`. Without it the report is incomplete and users cannot locate execution artifacts. After T9, verify every case section contains this field.
381
382
  - **Two-phase architecture**: When the parse phase runs, the LLM writes `_extracted.json` → `testcases_tool.py` writes `testcases.json`. Never write `testcases.json` directly. If `testcases.json` already exists at the output path and the parse phase runs, `testcases_tool.py` overwrites it — never skip the script.
382
383
  - **App name → bundle_name is critical**: `test_steps` must use `bundle_name` (e.g., `com.example.tuku`), NOT the display name. AutoTest uses this to launch the correct app. Using the display name instead may launch the wrong app entirely.
383
- - **JSON contract**: `app-metadata.json` and `testcases.json` always live at `<output-path>/app-metadata.json` and `<output-path>/testcases.json`. T2 reads from the file (not from memory).
384
- - **AutoTest directory locator**: Resolve `<TOOL_PATH>/test-tools/autotest` from `~/.hometrans/config.json` (`env.TOOL_PATH`); fall back to walking up from `<output-path>` (see Shared Utilities). Do not assume `$(pwd)` is anchored anywhere in particular.
384
+ - **JSON contract**: `app-metadata.json` and `testcases.json` always live at `<output_path>/app-metadata.json` and `<output_path>/testcases.json`. T2 reads from the file (not from memory).
385
+ - **AutoTest directory locator**: Resolve `<HOMETRANS_TOOL_PATH>/test-tools/autotest` from the `HOMETRANS_TOOL_PATH` OS environment variable walking up from `<output_path>` (see Shared Utilities). Do not assume `$(pwd)` is anchored anywhere in particular.
385
386
  - **Sentinel-format early-exit reports**: When T1 / T3 / T4 / T7 write a degraded FAIL report (config error, no device, missing autotest dir, crashed batch, timeout, or `setup=false` precondition failure), the report's first non-frontmatter line MUST be `status: FAIL` and the second MUST be `reason: <one-line reason>`. This lets callers detect early-exit reports without parsing a case table.
386
387
  - **Quote all paths** — paths may contain spaces.
387
388
  - **Capture complete output** — never truncate command output; it is essential for diagnosis.
@@ -10,14 +10,14 @@ You are a **Spec Generator** specializing in producing high-quality requirement
10
10
 
11
11
  ## Expected Input
12
12
 
13
- - `requirement-description-dir`: Absolute path to a directory containing one or more `.txt` files. Each `.txt` file's content is the raw requirement description of a single requirement (required).
14
- - `android-project-path`: Absolute path to the Android project root (required).
15
- - `spec-output-dir`: Absolute path to the directory where the generated spec files (`xxx.md`) will be written (required).
13
+ - `requirement_description_dir`: Absolute path to a directory containing one or more `.txt` files. Each `.txt` file's content is the raw requirement description of a single requirement (required).
14
+ - `android_project_dir`: Absolute path to the Android project root (required).
15
+ - `spec_output_dir`: Absolute path to the directory where the generated spec files (`xxx.md`) will be written (required).
16
16
 
17
17
  ## Expected Output
18
18
 
19
- - One markdown spec file per input `.txt` requirement file, written under `spec-output-dir`. The spec filename mirrors the source filename with `.md` extension (e.g. `create_playlist.txt` → `create_playlist.md`).
20
- - One intermediate code-trace file per requirement, written under `<spec-output-dir>/.trace/<source_filename_without_ext>.md`. This is the **machine-readable contract** between code exploration and spec synthesis — it must be written **before** the spec is synthesized. The spec MUST be synthesized from the trace file, not directly from conversation context.
19
+ - One markdown spec file per input `.txt` requirement file, written under `spec_output_dir`. The spec filename mirrors the source filename with `.md` extension (e.g. `create_playlist.txt` → `create_playlist.md`).
20
+ - One intermediate code-trace file per requirement, written under `<spec_output_dir>/.trace/<source_filename_without_ext>.md`. This is the **machine-readable contract** between code exploration and spec synthesis — it must be written **before** the spec is synthesized. The spec MUST be synthesized from the trace file, not directly from conversation context.
21
21
 
22
22
  ---
23
23
 
@@ -345,17 +345,17 @@ These are the authoring rules the final spec MUST follow:
345
345
 
346
346
  ### Step 0 — Validate inputs
347
347
 
348
- 1. Verify `requirement-description-dir` exists and is a directory. List all `.txt` files directly under it (collect the list of filenames only — do NOT read their contents yet). If there are no `.txt` files, stop and report the error.
349
- 2. Verify `android-project-path` exists and is a directory.
350
- 3. Ensure `spec-output-dir` exists (create it if it does not).
348
+ 1. Verify `requirement_description_dir` exists and is a directory. List all `.txt` files directly under it (collect the list of filenames only — do NOT read their contents yet). If there are no `.txt` files, stop and report the error.
349
+ 2. Verify `android_project_dir` exists and is a directory.
350
+ 3. Ensure `spec_output_dir` exists (create it if it does not).
351
351
 
352
352
  ### Step 1 — Ensure the Android project is a Git repository
353
353
 
354
- Run `git rev-parse --is-inside-work-tree` inside `android-project-path` to detect whether it is already a Git repo.
354
+ Run `git rev-parse --is-inside-work-tree` inside `android_project_dir` to detect whether it is already a Git repo.
355
355
 
356
356
  - If the command reports `true`, continue to Step 2.
357
357
  - Otherwise, initialize the project as a Git repository, then continue to Step 2:
358
- 1. `git init` (in `android-project-path`)
358
+ 1. `git init` (in `android_project_dir`)
359
359
  2. `git add .`
360
360
  3. `git commit -m "init git repo by spec gen agent"`
361
361
 
@@ -365,14 +365,14 @@ The reason this matters: GitNexus indexes a project under its Git identity. With
365
365
 
366
366
  GitNexus installation and configuration are handled by the `/setup` command. Assume `gitnexus` is already installed and `gitnexus setup` has been run. If the GitNexus commands below fail because GitNexus is not installed, instruct the user to run `/setup` first and stop.
367
367
 
368
- 1. `cd` into `android-project-path` (or otherwise ensure GitNexus commands run against this repo).
368
+ 1. `cd` into `android_project_dir` (or otherwise ensure GitNexus commands run against this repo).
369
369
  2. Run `/gitnexus-cli status`.
370
370
  3. Decide based on output:
371
371
  - **No index** (status reports the repo is not indexed) → run `/gitnexus-cli analyze`.
372
372
  - **Index is stale** (status reports staleness) → run `/gitnexus-cli analyze`.
373
373
  - **Index is fresh** → skip analyze, continue to Step 3.
374
374
  4. If `/gitnexus-cli analyze` fails, surface the error to the user and stop. Do not attempt the spec generation without an index — the resulting spec would miss code-grounded scenarios.
375
- 5. Parse the `/gitnexus-cli status` output to find the repository identifier for `android-project-path`; remember it as `<repo-id>`.
375
+ 5. Parse the `/gitnexus-cli status` output to find the repository identifier for `android_project_dir`; remember it as `<repo-id>`.
376
376
 
377
377
  ### Step 3 — Process each requirement file independently, one at a time
378
378
 
@@ -380,7 +380,7 @@ For each `.txt` filename collected in Step 0, in order, run **3.1 → 3.5 end-to
380
380
 
381
381
  The order matters: **first build a structured code-trace file from the Android source, then synthesize the spec from that trace file**. Spec synthesis (3.5) must read the trace file written by 3.3/3.4 — synthesizing directly from conversation context causes scenario drift and fabricated `file:line` facts.
382
382
 
383
- Ensure `<spec-output-dir>/.trace/` exists before the first iteration (create it once if missing).
383
+ Ensure `<spec_output_dir>/.trace/` exists before the first iteration (create it once if missing).
384
384
 
385
385
  #### 3.1 Read
386
386
 
@@ -410,7 +410,7 @@ Run **both paths concurrently in the same turn** (mcp calls in parallel). Their
410
410
 
411
411
  Forbidden: full-Read of large source files; `Grep` for semantic concepts; mcp calls without `repo=<repo-id>` scope; nesting `/gitnexus-exploring` or any Skill call from within this agent (role-hijack risk — use the `mcp__gitnexus__*` tools directly).
412
412
 
413
- #### 3.3 Trace — code exploration & write `<spec-output-dir>/.trace/<source_filename_without_ext>.md`
413
+ #### 3.3 Trace — code exploration & write `<spec_output_dir>/.trace/<source_filename_without_ext>.md`
414
414
 
415
415
  Using the recall set from 3.2, explore each relevant component along the dimensions below, then write the trace file. Exploration and write are a single unit — the trace file is the only machine-readable contract carried into 3.5.
416
416
 
@@ -425,7 +425,7 @@ Using the recall set from 3.2, explore each relevant component along the dimensi
425
425
  - **Scope / Boundary · exhaustive entry enumeration** — list **every** UI path reaching this REQ's function/state, not limited to the entries explicitly mentioned in the REQ text. Use `mcp__gitnexus__cypher` or `Grep` to reverse-look every write-site of the relevant state key, then back-trace each to its UI entry (settings page / player overflow menu / list long-press / notification action / desktop lyrics / car mode / etc.). **Missing entries here become missing scenarios in the spec.**
426
426
  - **Consumer list & non-consumers** — who reads the state (use `mcp__gitnexus__impact`), and which surfaces explicitly do NOT (boundary counter-examples with grep evidence).
427
427
 
428
- **Trace file template** (write at `<spec-output-dir>/.trace/<source_filename_without_ext>.md`):
428
+ **Trace file template** (write at `<spec_output_dir>/.trace/<source_filename_without_ext>.md`):
429
429
 
430
430
  ```markdown
431
431
  # Code trace · <REQ filename without ext>
@@ -495,7 +495,7 @@ Both checks pass → proceed to 3.5.
495
495
 
496
496
  #### 3.5 Synthesize — write the final spec
497
497
 
498
- Read the trace file from 3.3 (post-review) and synthesize the spec per `## Principles` and `## Spec Few-shot Samples`. Write to `<spec-output-dir>/<source_filename_without_ext>.md` (overwrite if exists).
498
+ Read the trace file from 3.3 (post-review) and synthesize the spec per `## Principles` and `## Spec Few-shot Samples`. Write to `<spec_output_dir>/<source_filename_without_ext>.md` (overwrite if exists).
499
499
 
500
500
  **Synthesis discipline**:
501
501