@guanlin4924/devflow-pi 0.1.92 → 0.1.94

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 (156) hide show
  1. package/README.md +6 -6
  2. package/package.json +1 -1
  3. package/plugins/devflow-core/extensions/devflow-core.ts +87 -33
  4. package/plugins/devflow-core/runtime/hooks/context_sync_gate.py +3 -3
  5. package/plugins/devflow-core/runtime/hooks/hook_common.py +65 -11
  6. package/plugins/devflow-core/runtime/hooks/start.py +13 -13
  7. package/plugins/devflow-core/skills/wireframe-proposal/SKILL.md +2 -2
  8. package/plugins/devflow-core/skills/wireframe-validate/SKILL.md +4 -4
  9. package/plugins/devflow-core/skills/workflow-orchestrator/SKILL.md +19 -19
  10. package/plugins/devflow-core/skills/workflow-orchestrator/agents/openai.yaml +2 -2
  11. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/acceptance_test_runner.py +5 -5
  12. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +9 -9
  13. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/api_test_matrix.py +2 -2
  14. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_assessment.rb +1 -1
  15. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_brief.rb +1 -1
  16. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_feasibility.rb +1 -1
  17. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_invalidation.rb +5 -5
  18. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_commit.rb +4 -4
  19. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_validate.py +1 -1
  20. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_source_resolver.rb +4 -4
  21. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/checker_adapter.rb +7 -7
  22. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/control_io.rb +51 -7
  23. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/cross_track_consistency_check.rb +1 -1
  24. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_contract.rb +6 -6
  25. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/gate_runtime.rb +3 -3
  26. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_state.rb +5 -5
  27. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_workflow.rb +5 -5
  28. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/inspect_state.rb +13 -13
  29. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/machine_evidence.rb +3 -3
  30. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/manage_lessons.rb +7 -7
  31. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/parallel_recover.rb +2 -2
  32. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/parallel_run.rb +3 -3
  33. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/phase_ownership.rb +6 -6
  34. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/repair_control_plane.rb +1 -1
  35. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_coverage.rb +1 -1
  36. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_graph.rb +3 -3
  37. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/review_preflight.py +3 -3
  38. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/review_run.py +18 -18
  39. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/runtime_context_collector.rb +3 -3
  40. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/session_rollover.rb +4 -4
  41. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/static_runtime_context_collector.rb +2 -2
  42. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/sync_artifacts.rb +5 -5
  43. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/tdd_evidence.py +3 -3
  44. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_command_policy.py +2 -2
  45. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_task_binding_check.py +3 -3
  46. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/update_triage_route.rb +3 -3
  47. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +6 -6
  48. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/wireframe_commit.rb +5 -5
  49. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/wireframe_validate.py +1 -1
  50. package/plugins/devflow-core/skills/workflow-orchestrator/templates/acceptance-remediation.yaml +12 -12
  51. package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml +205 -205
  52. package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +3 -3
  53. package/plugins/devflow-core/skills/workflow-pipeline/references/pipeline-flow.md +10 -10
  54. package/plugins/devflow-core/skills/workflow-project-context/SKILL.md +14 -14
  55. package/plugins/devflow-core/skills/workflow-project-context/assets/agents-md-template.md +7 -7
  56. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-backend-spec-template.md +4 -4
  57. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-frontend-spec-template.md +4 -4
  58. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-navigation-template.md +1 -1
  59. package/plugins/devflow-core/skills/workflow-project-context/assets/context-domain-index-template.md +4 -4
  60. package/plugins/devflow-core/skills/workflow-project-context/assets/context-spec-index-template.md +10 -10
  61. package/plugins/devflow-core/skills/workflow-project-context/assets/execution-contract-template.md +2 -2
  62. package/plugins/devflow-core/skills/workflow-project-context/assets/navigation-index-template.md +18 -18
  63. package/plugins/devflow-core/skills/workflow-project-context/assets/project-initialization-template.md +32 -32
  64. package/plugins/devflow-core/skills/workflow-project-context/assets/rules-index-template.md +30 -30
  65. package/plugins/devflow-core/skills/workflow-project-context/assets/state-template.md +7 -7
  66. package/plugins/devflow-core/skills/workflow-project-context/references/navigation-guide.md +37 -37
  67. package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization.py +22 -17
  68. package/plugins/devflow-design/skills/workflow-api-call-guide/SKILL.md +4 -4
  69. package/plugins/devflow-design/skills/workflow-api-contract/SKILL.md +8 -8
  70. package/plugins/devflow-design/skills/workflow-api-supplement/SKILL.md +5 -5
  71. package/plugins/devflow-design/skills/workflow-architecture-feasibility/SKILL.md +1 -1
  72. package/plugins/devflow-design/skills/workflow-backend-tech-spec/SKILL.md +39 -39
  73. package/plugins/devflow-design/skills/workflow-backend-tech-spec/assets/backend-spec-template.md +10 -10
  74. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/affected-module-exploration.md +2 -2
  75. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/code-explore-guide.md +1 -1
  76. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/project-rule-contract.md +20 -20
  77. package/plugins/devflow-design/skills/workflow-design-rule-pack/SKILL.md +8 -8
  78. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/index.md +3 -3
  79. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/accessibility.md +2 -2
  80. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/component-library.md +2 -2
  81. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/design-systems.md +1 -1
  82. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/responsive-grid.md +2 -2
  83. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/stack-guidelines.md +6 -6
  84. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/ux-patterns.md +2 -2
  85. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tokens/project-tokens.md +1 -1
  86. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/SKILL.md +12 -12
  87. package/plugins/devflow-design/skills/workflow-design-rule-pack/scripts/install.py +2 -2
  88. package/plugins/devflow-design/skills/workflow-feature-breakdown/SKILL.md +30 -30
  89. package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/output-template.md +2 -2
  90. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/SKILL.md +41 -41
  91. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/assets/frontend-spec-template.md +15 -15
  92. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/affected-module-exploration.md +2 -2
  93. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/project-rule-contract.md +25 -25
  94. package/plugins/devflow-design/skills/workflow-integration-verify/SKILL.md +13 -13
  95. package/plugins/devflow-design/skills/workflow-ui-spec/SKILL.md +23 -23
  96. package/plugins/devflow-design/skills/workflow-ui-spec/assets/ui-spec-template.md +3 -3
  97. package/plugins/devflow-implementation/agents/implementation-worker.md +2 -2
  98. package/plugins/devflow-implementation/skills/workflow-bug-fix/SKILL.md +9 -9
  99. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/lesson-format.md +2 -2
  100. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/root-cause-ladder.md +1 -1
  101. package/plugins/devflow-implementation/skills/workflow-change-plan/SKILL.md +17 -17
  102. package/plugins/devflow-implementation/skills/workflow-change-plan/references/code-conventions.md +1 -1
  103. package/plugins/devflow-implementation/skills/workflow-change-plan/references/output-template.md +3 -3
  104. package/plugins/devflow-implementation/skills/workflow-change-plan/references/project-rule-contract.md +16 -16
  105. package/plugins/devflow-implementation/skills/workflow-execute-phase/SKILL.md +38 -38
  106. package/plugins/devflow-implementation/skills/workflow-execute-phase/references/execute-phase.md +1 -1
  107. package/plugins/devflow-intel/agents/project-scout.md +3 -1
  108. package/plugins/devflow-intel/extensions/devflow-intel.ts +20 -19
  109. package/plugins/devflow-intel/skills/code-index-query/SKILL.md +8 -6
  110. package/plugins/devflow-intel/skills/workflow-code-index/SKILL.md +12 -12
  111. package/plugins/devflow-intel/skills/workflow-code-index/references/discovery.md +2 -2
  112. package/plugins/devflow-intel/skills/workflow-code-index/references/query-guide.md +1 -1
  113. package/plugins/devflow-intel/skills/workflow-code-index/scripts/code_index.py +8 -8
  114. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/discovery.py +2 -2
  115. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/scanner.py +4 -1
  116. package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/project_binding_check.py +4 -4
  117. package/plugins/devflow-intel/skills/workflow-context-sync/SKILL.md +14 -14
  118. package/plugins/devflow-intel/skills/workflow-context-sync/scripts/context_sync_cursor.py +2 -2
  119. package/plugins/devflow-intel/skills/workflow-update-navigation/SKILL.md +26 -26
  120. package/plugins/devflow-intel/skills/workflow-update-navigation/references/incremental-update-guide.md +2 -2
  121. package/plugins/devflow-quality/skills/code-review/SKILL.md +13 -13
  122. package/plugins/devflow-quality/skills/code-review/references/spec-checklist.md +1 -1
  123. package/plugins/devflow-quality/skills/workflow-acceptance-test-design/SKILL.md +8 -8
  124. package/plugins/devflow-quality/skills/workflow-gen-test-guide/SKILL.md +6 -6
  125. package/plugins/devflow-quality/skills/workflow-gen-test-guide/legacy/SKILL.md +14 -14
  126. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/SKILL.md +23 -23
  127. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/codebase-discovery.md +9 -9
  128. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/project-dsl-contract.md +1 -1
  129. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/compile_dsl.py +2 -2
  130. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/discover_codebases.py +2 -2
  131. package/plugins/devflow-quality/skills/workflow-release-closeout/SKILL.md +15 -15
  132. package/plugins/devflow-quality/skills/workflow-run-acceptance-tests/SKILL.md +5 -5
  133. package/plugins/devflow-requirements/skills/requirement-feasibility-review/SKILL.md +1 -1
  134. package/plugins/devflow-requirements/skills/workflow-demand-clarify/SKILL.md +10 -10
  135. package/plugins/devflow-requirements/skills/workflow-domain-modeling/SKILL.md +25 -25
  136. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/SKILL.md +49 -49
  137. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/assets/baseline-template.md +22 -22
  138. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/antipatterns.md +3 -3
  139. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/challenge-review-guide.md +3 -3
  140. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/project-context-guide.md +11 -11
  141. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/questioning.md +1 -1
  142. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/requirement-review-checklist.md +4 -4
  143. package/plugins/devflow-requirements/skills/workflow-requirement-triage/SKILL.md +16 -16
  144. package/plugins/devflow-requirements/skills/workflow-wayfinder/SKILL.md +6 -6
  145. package/src/cli.ts +15 -0
  146. package/src/constants.ts +1 -1
  147. package/src/initialization-store.ts +3 -2
  148. package/src/project-context.ts +36 -14
  149. package/src/project-documents.ts +61 -61
  150. package/src/project-initializer.ts +23 -9
  151. package/src/project-layout.ts +217 -0
  152. package/src/runtime.ts +3 -3
  153. package/templates/commands/start.md +4 -4
  154. package/templates/omp/AGENTS.md +1 -1
  155. package/templates/omp/hook-config.json +7 -7
  156. package/templates/omp/index-policy.json +8 -8
@@ -17,7 +17,7 @@ options = {
17
17
  step: nil,
18
18
  status: "not_started",
19
19
  track: nil,
20
- state: ".planning/STATE.md",
20
+ state: ".devflow/planning/STATE.md",
21
21
  write: false,
22
22
  force: false,
23
23
  json: false
@@ -58,7 +58,7 @@ unless PhaseOwnership.valid_slug?(phase)
58
58
  puts JSON.pretty_generate({ "ok" => false, "reason" => "invalid_phase", "message" => "phase must be a safe non-empty slug" })
59
59
  exit 0
60
60
  end
61
- workflow_config = ".planning/workflows/#{options[:flow]}.yaml"
61
+ workflow_config = ".devflow/planning/workflows/#{options[:flow]}.yaml"
62
62
  workflow_path = File.expand_path(workflow_config, root)
63
63
  unless options[:flow].is_a?(String) && options[:flow].match?(/\A[A-Za-z0-9][A-Za-z0-9_-]*\z/)
64
64
  puts JSON.pretty_generate({
@@ -120,9 +120,9 @@ state = {
120
120
  "completed_steps" => [],
121
121
  "pending_steps" => pending_steps,
122
122
  "active_outputs" => {
123
- "requirement_baseline" => ".planning/requirements/baseline.md",
124
- "feature_dir" => ".planning/features/#{feature}/",
125
- "phase_dir" => ".planning/phases/#{phase}/"
123
+ "requirement_baseline" => ".devflow/planning/requirements/baseline.md",
124
+ "feature_dir" => ".devflow/planning/features/#{feature}/",
125
+ "phase_dir" => ".devflow/planning/phases/#{phase}/"
126
126
  }
127
127
  }
128
128
 
@@ -19,7 +19,7 @@ end.parse!
19
19
  root = Dir.pwd
20
20
  skill_root = File.expand_path("..", __dir__)
21
21
  template_dir = File.join(skill_root, "templates")
22
- state_path = File.join(root, ".planning", "STATE.md")
22
+ state_path = File.join(root, ".devflow/planning", "STATE.md")
23
23
 
24
24
  def front_matter(markdown)
25
25
  match = markdown.match(/\A---\n(.*?)\n---\n/m)
@@ -42,7 +42,7 @@ end
42
42
  def active_workflow_target?(state, target_path)
43
43
  return false unless state
44
44
 
45
- active = state["workflow_config"] || ".planning/workflows/#{state["current_flow"]}.yaml"
45
+ active = state["workflow_config"] || ".devflow/planning/workflows/#{state["current_flow"]}.yaml"
46
46
  active == target_path
47
47
  end
48
48
 
@@ -57,9 +57,9 @@ def state_step_mismatch?(state, template_path)
57
57
  end
58
58
 
59
59
  targets = {
60
- "feature-development.yaml" => ".planning/workflows/feature-development.yaml",
61
- "acceptance-remediation.yaml" => ".planning/workflows/acceptance-remediation.yaml",
62
- "workflows-README.md" => ".planning/workflows/README.md"
60
+ "feature-development.yaml" => ".devflow/planning/workflows/feature-development.yaml",
61
+ "acceptance-remediation.yaml" => ".devflow/planning/workflows/acceptance-remediation.yaml",
62
+ "workflows-README.md" => ".devflow/planning/workflows/README.md"
63
63
  }
64
64
 
65
65
  blocked_target_paths = if options[:force] && options[:write] && !options[:allow_state_mismatch]
@@ -15,7 +15,7 @@ OptionParser.new do |opts|
15
15
  end.parse!
16
16
 
17
17
  root = Dir.pwd
18
- state_path = options[:state] ? File.expand_path(options[:state], root) : File.join(root, ".planning", "STATE.md")
18
+ state_path = options[:state] ? File.expand_path(options[:state], root) : File.join(root, ".devflow/planning", "STATE.md")
19
19
 
20
20
  def fail_result(reason, details = {})
21
21
  {
@@ -64,9 +64,9 @@ end
64
64
 
65
65
  def project_context_missing?(root)
66
66
  required_paths = [
67
- File.join(root, ".planning", "PROJECT.md"),
68
- File.join(root, ".planning", "navigation", "INDEX.md"),
69
- File.join(root, ".context", "spec", "index.md")
67
+ File.join(root, ".devflow/planning", "PROJECT.md"),
68
+ File.join(root, ".devflow/planning", "navigation", "INDEX.md"),
69
+ File.join(root, ".devflow/context", "spec", "index.md")
70
70
  ]
71
71
 
72
72
  required_paths.any? { |path| !File.exist?(path) }
@@ -325,10 +325,10 @@ result =
325
325
  "missing_project_context",
326
326
  path: state_path,
327
327
  missing: [
328
- ".planning/STATE.md",
329
- ".planning/PROJECT.md",
330
- ".planning/navigation/INDEX.md",
331
- ".context/spec/index.md"
328
+ ".devflow/planning/STATE.md",
329
+ ".devflow/planning/PROJECT.md",
330
+ ".devflow/planning/navigation/INDEX.md",
331
+ ".devflow/context/spec/index.md"
332
332
  ]
333
333
  )
334
334
  else
@@ -367,9 +367,9 @@ result =
367
367
  project_context_result(
368
368
  "incomplete_project_context",
369
369
  missing: [
370
- ".planning/PROJECT.md",
371
- ".planning/navigation/INDEX.md",
372
- ".context/spec/index.md"
370
+ ".devflow/planning/PROJECT.md",
371
+ ".devflow/planning/navigation/INDEX.md",
372
+ ".devflow/context/spec/index.md"
373
373
  ]
374
374
  )
375
375
  else
@@ -385,7 +385,7 @@ result =
385
385
  )
386
386
  else
387
387
  workflow_path = state["workflow_config"] ||
388
- File.join(".planning", "workflows", "#{state["current_flow"]}.yaml")
388
+ File.join(".devflow/planning", "workflows", "#{state["current_flow"]}.yaml")
389
389
  abs_workflow_path = File.join(root, workflow_path)
390
390
 
391
391
  if !File.exist?(abs_workflow_path)
@@ -641,7 +641,7 @@ result =
641
641
  missing_outputs: missing_outputs,
642
642
  checkpoint_meta_errors: checkpoint_meta_errors,
643
643
  resume_behavior: checkpoint && checkpoint["resume_behavior"],
644
- next_intent: ".planning/.next-intent"
644
+ next_intent: ".devflow/planning/.next-intent"
645
645
  )
646
646
  elsif parallel_window
647
647
  base.merge(action: "run_parallel_window")
@@ -30,7 +30,7 @@ abort "feature, step and --write are required" unless options[:feature] && optio
30
30
  abort "invalid feature" unless RequirementGraph.valid_feature?(options[:feature])
31
31
 
32
32
  def state_front_matter(root)
33
- document = File.read(File.join(root, ".planning/STATE.md"))
33
+ document = File.read(File.join(root, ".devflow/planning/STATE.md"))
34
34
  front = document.match(/\A---\n(.*?)\n---/m)&.[](1)
35
35
  raise "STATE.md has no YAML front matter" unless front
36
36
  YAML.safe_load(front, permitted_classes: [], aliases: false)
@@ -62,7 +62,7 @@ def independent_evidence(root, feature, step, state, workflow, graph, files, che
62
62
  # cannot manufacture proof that an engine did not invoke AI.
63
63
  binding_attempt = binding && binding["attempt"]
64
64
  event_name = binding_attempt.nil? ? "#{step}.engine-events.jsonl" : "#{step}.attempt-#{binding_attempt}.engine-events.jsonl"
65
- event_path = File.join(".planning", "evidence", feature, event_name)
65
+ event_path = File.join(".devflow/planning", "evidence", feature, event_name)
66
66
  event_absolute, = DevflowControlIO.resolve_control_path(root, event_path, :artifact)
67
67
  events = if File.file?(event_absolute)
68
68
  File.foreach(event_absolute).first(10_000).each_with_object([]) do |line, parsed|
@@ -259,7 +259,7 @@ begin
259
259
  "gate_mode" => gate.empty? ? "observe" : gate
260
260
  }.compact
261
261
  suffix = binding ? ".attempt-#{binding["attempt"]}.branch-#{Digest::SHA256.hexdigest(binding["branch_id"].to_s)[0, 12]}" : ""
262
- destination = File.join(root, ".planning/evidence", options[:feature], "#{options[:step]}#{suffix}.machine.json")
262
+ destination = File.join(root, ".devflow/planning/evidence", options[:feature], "#{options[:step]}#{suffix}.machine.json")
263
263
  DevflowControlIO.atomic_write(destination, JSON.pretty_generate(pack) + "\n")
264
264
  result = { "ok" => true, "path" => destination.sub("#{root}/", ""), "complete" => pack["complete"], "state_revision" => pack["state_revision"], "graph_revision" => pack["graph_revision"], "checkers" => checker_results, "checkpoint_meta_errors" => checkpoint_meta_errors, "parallel_binding" => binding }
265
265
  rescue StandardError => error
@@ -31,7 +31,7 @@ OptionParser.new do |opts|
31
31
  end.parse!
32
32
 
33
33
  root = Dir.pwd
34
- state_path = options[:state] ? File.expand_path(options[:state], root) : File.join(root, ".planning", "STATE.md")
34
+ state_path = options[:state] ? File.expand_path(options[:state], root) : File.join(root, ".devflow/planning", "STATE.md")
35
35
 
36
36
  def front_matter(markdown)
37
37
  match = markdown.match(/\A---\n(.*?)\n---\n/m)
@@ -51,19 +51,19 @@ def load_state(path)
51
51
  end
52
52
 
53
53
  def workflow_path_for(state)
54
- state["workflow_config"] || File.join(".planning", "workflows", "#{state.fetch("current_flow")}.yaml")
54
+ state["workflow_config"] || File.join(".devflow/planning", "workflows", "#{state.fetch("current_flow")}.yaml")
55
55
  end
56
56
 
57
57
  def configured_policy(workflow)
58
58
  workflow["lessons_policy"] || {
59
59
  "sources" => [
60
- { "path" => ".context/lessons/README.md", "required" => false },
61
- { "path" => ".planning/lessons/README.md", "required" => false }
60
+ { "path" => ".devflow/context/lessons/README.md", "required" => false },
61
+ { "path" => ".devflow/planning/lessons/README.md", "required" => false }
62
62
  ],
63
63
  "selection" => { "max_candidates" => 5, "min_score" => 1 },
64
64
  "write" => {
65
- "default_dir" => ".context/lessons",
66
- "index_path" => ".context/lessons/README.md"
65
+ "default_dir" => ".devflow/context/lessons",
66
+ "index_path" => ".devflow/context/lessons/README.md"
67
67
  }
68
68
  }
69
69
  end
@@ -167,7 +167,7 @@ end
167
167
 
168
168
  def write_template(root, policy, state, title, source, write)
169
169
  write_config = policy["write"] || {}
170
- dir = write_config["default_dir"] || ".context/lessons"
170
+ dir = write_config["default_dir"] || ".devflow/context/lessons"
171
171
  index_path = write_config["index_path"] || File.join(dir, "README.md")
172
172
  file_name = "#{Date.today}-#{slug_for(title)}.md"
173
173
  rel_path = File.join(dir, file_name)
@@ -159,7 +159,7 @@ rescue JSON::ParserError => error
159
159
  end
160
160
 
161
161
  def audit_path(root, feature)
162
- DevflowControlIO.resolve_control_path(root, ".planning/evidence/#{feature}/parallel-recovery.jsonl", :artifact).first
162
+ DevflowControlIO.resolve_control_path(root, ".devflow/planning/evidence/#{feature}/parallel-recovery.jsonl", :artifact).first
163
163
  end
164
164
 
165
165
  def append_audit(root, feature, payload, lock: nil)
@@ -233,7 +233,7 @@ begin
233
233
  validation_records = []
234
234
  project_lock = DevflowControlIO.acquire_project_lock(root)
235
235
  begin
236
- state_path, = DevflowControlIO.resolve_control_path(root, ".planning/STATE.md", :state)
236
+ state_path, = DevflowControlIO.resolve_control_path(root, ".devflow/planning/STATE.md", :state)
237
237
  state_yaml = front_matter(File.read(state_path))
238
238
  raise ArgumentError, "STATE.md has no YAML front matter" unless state_yaml
239
239
  state = YAML.safe_load(state_yaml, permitted_classes: [Date, Time], aliases: false)
@@ -29,7 +29,7 @@ module ParallelRun
29
29
  end
30
30
 
31
31
  def path(root, feature)
32
- File.join(root, ".planning", "parallel", safe_feature(feature), "branches.yaml")
32
+ File.join(root, ".devflow/planning", "parallel", safe_feature(feature), "branches.yaml")
33
33
  end
34
34
 
35
35
  def load(root, feature)
@@ -94,7 +94,7 @@ module ParallelRun
94
94
  state
95
95
  end
96
96
 
97
- def prepare(root:, feature:, workflow_window:, state_revision:, branches:, task_ids: {}, state_path: ".planning/STATE.md")
97
+ def prepare(root:, feature:, workflow_window:, state_revision:, branches:, task_ids: {}, state_path: ".devflow/planning/STATE.md")
98
98
  lock = DevflowControlIO.acquire_project_lock(root)
99
99
  begin
100
100
  raise ArgumentError, "parallel run already exists" if load(root, feature)
@@ -204,7 +204,7 @@ end
204
204
 
205
205
  if $PROGRAM_NAME == __FILE__
206
206
  begin
207
- options = { action: nil, feature: nil, state_revision: nil, run_revision: nil, branch_id: nil, status: nil, workflow_window: nil, branches: [], state_path: ".planning/STATE.md", json: false }
207
+ options = { action: nil, feature: nil, state_revision: nil, run_revision: nil, branch_id: nil, status: nil, workflow_window: nil, branches: [], state_path: ".devflow/planning/STATE.md", json: false }
208
208
  OptionParser.new do |opts|
209
209
  opts.on("--action ACTION", %w[inspect prepare update retry rebase serial-fallback]) { |value| options[:action] = value }
210
210
  opts.on("--feature FEATURE") { |value| options[:feature] = value }
@@ -11,7 +11,7 @@ require "yaml"
11
11
  require_relative "control_io"
12
12
 
13
13
  module PhaseOwnership
14
- REGISTRY_PATH = ".planning/phase-ownership.yaml"
14
+ REGISTRY_PATH = ".devflow/planning/phase-ownership.yaml"
15
15
  PHASE_SLUG = /\A[A-Za-z0-9][A-Za-z0-9_-]*\z/
16
16
  module_function
17
17
 
@@ -45,11 +45,11 @@ module PhaseOwnership
45
45
  def valid_owner?(owner, phase: nil)
46
46
  owner.is_a?(Hash) && valid_slug?(owner["phase"]) && (phase.nil? || owner["phase"] == phase) &&
47
47
  valid_feature?(owner["feature"]) && owner["flow"].is_a?(String) && !owner["flow"].empty? &&
48
- owner["state_path"] == ".planning/STATE.md" && %w[active completed].include?(owner["status"])
48
+ owner["state_path"] == ".devflow/planning/STATE.md" && %w[active completed].include?(owner["status"])
49
49
  end
50
50
 
51
51
  def nonempty_phase_dirs(root)
52
- Dir.glob(File.join(root, ".planning", "phases", "*")).select do |path|
52
+ Dir.glob(File.join(root, ".devflow/planning", "phases", "*")).select do |path|
53
53
  File.directory?(path) && !Dir.children(path).empty?
54
54
  end.map { |path| File.basename(path) }
55
55
  end
@@ -84,8 +84,8 @@ module PhaseOwnership
84
84
  return failure("phase_owned_by_another_feature", "requested phase is already owned by another feature", owner: current)
85
85
  end
86
86
 
87
- owner = current || { "phase" => phase, "feature" => feature, "flow" => flow, "state_path" => ".planning/STATE.md", "scope" => "global", "status" => "active" }
88
- owner = owner.merge("phase" => phase, "feature" => feature, "flow" => flow, "state_path" => ".planning/STATE.md", "scope" => "global", "status" => "active")
87
+ owner = current || { "phase" => phase, "feature" => feature, "flow" => flow, "state_path" => ".devflow/planning/STATE.md", "scope" => "global", "status" => "active" }
88
+ owner = owner.merge("phase" => phase, "feature" => feature, "flow" => flow, "state_path" => ".devflow/planning/STATE.md", "scope" => "global", "status" => "active")
89
89
  registry["owners"][phase] = owner
90
90
  registry["updated_at"] = Date.today.to_s
91
91
  DevflowControlIO.atomic_write(registry_path(root), registry.to_yaml) if write
@@ -114,7 +114,7 @@ module PhaseOwnership
114
114
  return failure("invalid_phase", "STATE.md current_phase must be a safe non-empty slug") unless valid_slug?(phase)
115
115
  owner = owner_override || registry["owners"][phase]
116
116
  return failure("missing_phase_owner", "STATE.md phase has no ownership record", phase: phase) unless valid_owner?(owner, phase: phase)
117
- unless owner["feature"] == feature && owner["flow"] == flow && owner["state_path"] == ".planning/STATE.md"
117
+ unless owner["feature"] == feature && owner["flow"] == flow && owner["state_path"] == ".devflow/planning/STATE.md"
118
118
  return failure("phase_owner_mismatch", "STATE.md does not match phase ownership record", owner: owner)
119
119
  end
120
120
  conflicting = registry["owners"].values.find { |entry| valid_owner?(entry) && entry["status"] == "active" && entry["phase"] != phase }
@@ -9,7 +9,7 @@ require_relative "control_io"
9
9
  require_relative "validate_state"
10
10
  require_relative "phase_ownership"
11
11
 
12
- options = { state: ".planning/STATE.md", expected_revision: nil, confirm: false, write: false, json: false }
12
+ options = { state: ".devflow/planning/STATE.md", expected_revision: nil, confirm: false, write: false, json: false }
13
13
  OptionParser.new do |opts|
14
14
  opts.banner = "Usage: repair_control_plane.rb --expected-revision N --confirm --write"
15
15
  opts.on("--state PATH") { |value| options[:state] = value }
@@ -14,7 +14,7 @@ module RequirementCoverage
14
14
  module_function
15
15
 
16
16
  def generate(root:, feature:, source:)
17
- state = YAML.safe_load(File.read(File.join(root, ".planning/STATE.md")).split(/^---\s*$/, 3)[1], permitted_classes: [Date], aliases: false)
17
+ state = YAML.safe_load(File.read(File.join(root, ".devflow/planning/STATE.md")).split(/^---\s*$/, 3)[1], permitted_classes: [Date], aliases: false)
18
18
  raise ArgumentError, "source generation requires the active wayfinder step" unless state["current_feature"] == feature && state["current_step"] == "requirement-wayfinder"
19
19
  source_path = File.realpath(File.expand_path(source, root))
20
20
  raise ArgumentError, "source must be a project file" unless source_path.start_with?(File.realpath(root) + File::SEPARATOR)
@@ -18,7 +18,7 @@ module RequirementGraph
18
18
  # graphs are migrated in memory and re-written only by this Core writer.
19
19
  SCHEMA_VERSION = 5
20
20
  SUPPORTED_SCHEMA_VERSIONS = [1, 2, 3, 4, SCHEMA_VERSION].freeze
21
- ROOT = ".planning/requirements"
21
+ ROOT = ".devflow/planning/requirements"
22
22
  KINDS = {
23
23
  "source" => "SRC", "code" => "CODE", "term" => "TERM", "object" => "OBJECT",
24
24
  "behavior" => "BEH", "requirement" => "REQ", "rule" => "BR", "boundary" => "BC",
@@ -56,7 +56,7 @@ module RequirementGraph
56
56
  end
57
57
 
58
58
  def active_feature(root)
59
- state_path = File.join(root, ".planning", "STATE.md")
59
+ state_path = File.join(root, ".devflow/planning", "STATE.md")
60
60
  return nil unless File.file?(state_path)
61
61
  front = File.read(state_path).match(/\A---\n(.*?)\n---/m)&.[](1)
62
62
  return nil unless front
@@ -553,7 +553,7 @@ module RequirementGraph
553
553
  end
554
554
  matrix["imported_graph_revision"] = graph["revision"]
555
555
  DevflowControlIO.atomic_write(matrix_path, JSON.pretty_generate(matrix) + "\n")
556
- template_path = File.join(root, ".planning", "features", graph["feature"], "api-acceptance-bindings.template.json")
556
+ template_path = File.join(root, ".devflow/planning", "features", graph["feature"], "api-acceptance-bindings.template.json")
557
557
  template = {
558
558
  "schema_version" => 1, "origin" => "core_api_test_matrix_template", "feature" => graph["feature"],
559
559
  "case_set_fingerprint" => matrix["case_set_fingerprint"],
@@ -81,7 +81,7 @@ def preflight(root: Path, feature: str, step: str, contract_path: str,
81
81
  return {"status": "human_confirmation", "evidence": evidence,
82
82
  "issues": [{"code": "STALE_WORKFLOW_SNAPSHOT"}]}
83
83
  workflow = load_workflow(workflow_path)
84
- state = load_state(within(root, ".planning/STATE.md"))
84
+ state = load_state(within(root, ".devflow/planning/STATE.md"))
85
85
  if state.get("revision") != current["state_revision"] or state.get("current_feature") != feature or state.get("current_step") != step:
86
86
  return {"status": "human_confirmation", "evidence": evidence,
87
87
  "issues": [{"code": "STALE_STATE_SNAPSHOT"}]}
@@ -100,7 +100,7 @@ def preflight(root: Path, feature: str, step: str, contract_path: str,
100
100
  else:
101
101
  issues.append({"code": "INVALID_WORKFLOW_INPUT", "detail": "unrecognized input obligation"})
102
102
  continue
103
- if required and relative != ".planning/execution-contract.md":
103
+ if required and relative != ".devflow/planning/execution-contract.md":
104
104
  derived.append({"path": render(relative), "producer": "existing"})
105
105
  for item in step_definition.get("outputs", []):
106
106
  if isinstance(item, dict) and item.get("required") is True and isinstance(item.get("path"), str):
@@ -113,7 +113,7 @@ def preflight(root: Path, feature: str, step: str, contract_path: str,
113
113
  "required_obligation_count": len(derived),
114
114
  "checker_ids": current.get("checker_ids", [])})
115
115
  if step == "code-review":
116
- graph_relative = f".planning/requirements/{feature}/governance.json"
116
+ graph_relative = f".devflow/planning/requirements/{feature}/governance.json"
117
117
  graph_path = within(root, graph_relative)
118
118
  if not graph_path.is_file():
119
119
  issues.append({"code": "CONFIRMED_EXPECTATIONS_UNAVAILABLE", "path": graph_relative})
@@ -109,7 +109,7 @@ def validate_authority(root: Path, feature: str, expectations: list) -> tuple[li
109
109
  issues.append(f"{item['id']}: authority_ref must identify a Core graph node and revision")
110
110
  continue
111
111
  node_id, revision = ref[len("core-graph:"):].rsplit("@", 1)
112
- graph_path = f".planning/requirements/{feature}/governance.json"
112
+ graph_path = f".devflow/planning/requirements/{feature}/governance.json"
113
113
  graph_file = safe_file(root, graph_path)
114
114
  authority = read_json(graph_file)
115
115
  node = next((n for n in authority.get("nodes", []) if isinstance(n, dict) and n.get("id") == node_id), None)
@@ -132,7 +132,7 @@ def validate_authority(root: Path, feature: str, expectations: list) -> tuple[li
132
132
 
133
133
 
134
134
  def db_open(root: Path) -> sqlite3.Connection:
135
- planning = root / ".planning"
135
+ planning = root / ".devflow/planning"
136
136
  if planning.is_symlink():
137
137
  raise ValueError("unsafe planning directory")
138
138
  directory = planning / "review-runs"
@@ -174,7 +174,7 @@ def response(status: str, chain_id: str | None, round_no: int, **details: Any) -
174
174
 
175
175
  def locate_index(root: Path, accepted: list, target_paths: list[str], questions: list[str]) -> dict:
176
176
  """Ask the index for bounded leads, never for authoritative conclusions."""
177
- index = root / ".planning" / "code-index"
177
+ index = root / ".devflow/planning" / "code-index"
178
178
  script = Path(__file__).resolve().parents[3].parent / "devflow-intel" / "skills" / "workflow-code-index" / "scripts" / "code_index.py"
179
179
  if not index.exists() or not script.exists():
180
180
  return {"status": "unavailable", "reason": "No local code-index snapshot; source evidence is independent"}
@@ -218,7 +218,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
218
218
  """Accept only a Core-owned TC result bound to the feature and frozen suite."""
219
219
  if not isinstance(evidence, dict):
220
220
  return False, "missing Core acceptance-test result reference"
221
- relative = f".planning/test-runs/{feature}/acceptance-results.json"
221
+ relative = f".devflow/planning/test-runs/{feature}/acceptance-results.json"
222
222
  if evidence.get("path") != relative or not isinstance(evidence.get("tc_id"), str):
223
223
  return False, "result must reference a Core acceptance TC for this feature"
224
224
  try:
@@ -226,7 +226,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
226
226
  if digest(result_file.read_bytes()) != evidence.get("sha256"):
227
227
  return False, "acceptance result hash mismatch"
228
228
  payload = read_json(result_file)
229
- suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
229
+ suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
230
230
  if payload.get("origin") != "core_acceptance_test_runner" or payload.get("feature") != feature:
231
231
  return False, "not a Core acceptance-test run"
232
232
  if payload.get("test_suite") != {"graph_revision": suite.get("graph_revision"), "fingerprint": suite.get("view_meta", {}).get("fingerprint")}:
@@ -252,7 +252,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
252
252
  def verify_core_impact(root: Path, feature: str, evidence: dict, impact: str, trigger: str) -> tuple[bool, str]:
253
253
  """A failed TC alone does not establish the reviewer's causal/impact label."""
254
254
  try:
255
- suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
255
+ suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
256
256
  node = next((n for n in suite.get("nodes", []) if isinstance(n, dict) and n.get("id") == evidence.get("tc_id")), None)
257
257
  data = node.get("data", {}) if node else {}
258
258
  if data.get("review_impact") == impact and data.get("review_trigger") == trigger:
@@ -263,7 +263,7 @@ def verify_core_impact(root: Path, feature: str, evidence: dict, impact: str, tr
263
263
 
264
264
 
265
265
  def declared_change_paths(root: Path, feature: str) -> tuple[set[str], str, str]:
266
- relative = f".planning/features/{feature}/变更清单.md"
266
+ relative = f".devflow/planning/features/{feature}/变更清单.md"
267
267
  source = safe_file(root, relative)
268
268
  declarations = re.findall(r"^\s*-\s*\*\*文件\*\*\s*[::]\s*(.+)$", source.read_text(encoding="utf-8"), re.MULTILINE)
269
269
  paths = set()
@@ -295,7 +295,7 @@ def verify_coverage(root: Path, feature: str, required: list[str], coverage_evid
295
295
  if not valid:
296
296
  issues.append(f"{tag}: {reason}")
297
297
  continue
298
- suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
298
+ suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
299
299
  node = next((n for n in suite.get("nodes", []) if isinstance(n, dict) and n.get("id") == ref["tc_id"]), None)
300
300
  types = {"scenario:normal": {"api", "page"}, "scenario:unauthorized": {"permission"}, "scenario:failure_rollback": {"resilience", "boundary"}, "scenario:compatibility": {"migration"}}
301
301
  data = node.get("data", {}) if node else {}
@@ -310,7 +310,7 @@ def verify_coverage(root: Path, feature: str, required: list[str], coverage_evid
310
310
 
311
311
  def suite_has_failures(root: Path, feature: str) -> bool:
312
312
  try:
313
- payload = read_json(safe_file(root, f".planning/test-runs/{feature}/acceptance-results.json"))
313
+ payload = read_json(safe_file(root, f".devflow/planning/test-runs/{feature}/acceptance-results.json"))
314
314
  return any(isinstance(item, dict) and item.get("status") != "passed" for item in payload.get("results", []))
315
315
  except (OSError, ValueError, TypeError, json.JSONDecodeError):
316
316
  return True
@@ -322,13 +322,13 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
322
322
  if not contract_id:
323
323
  return {"status": "human_confirmation", "reason": "Current Core review contract identity is required"}
324
324
  try:
325
- contract = read_json(safe_file(root, f".planning/contracts/{feature}/{contract_id}.json"))
325
+ contract = read_json(safe_file(root, f".devflow/planning/contracts/{feature}/{contract_id}.json"))
326
326
  if contract.get("origin") != "core_execution_contract" or contract.get("step") != "code-review" or contract.get("feature") != feature or contract.get("contract_id") != contract_id:
327
327
  return {"status": "core_contract_conflict", "reason": "Review contract identity is not a frozen Core code-review contract"}
328
328
  sys.path.insert(0, str(Path(__file__).resolve().parent))
329
329
  from review_preflight import load_state
330
- state = load_state(safe_file(root, ".planning/STATE.md"))
331
- graph = read_json(safe_file(root, f".planning/requirements/{feature}/governance.json"))
330
+ state = load_state(safe_file(root, ".devflow/planning/STATE.md"))
331
+ graph = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/governance.json"))
332
332
  workflow = safe_file(root, contract["workflow_path"])
333
333
  if (state.get("current_feature") != feature or state.get("current_step") != "code-review"
334
334
  or state.get("revision") != contract.get("state_revision")
@@ -337,7 +337,7 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
337
337
  return {"status": "stale_evidence", "reason": "Review contract differs from current Core state, graph, or workflow"}
338
338
  except (OSError, ValueError, KeyError, TypeError, ImportError, json.JSONDecodeError) as exc:
339
339
  return {"status": "human_confirmation", "reason": f"Current Core review contract cannot be verified: {exc}"}
340
- database = root / ".planning" / "review-runs" / "review-runs.sqlite"
340
+ database = root / ".devflow/planning" / "review-runs" / "review-runs.sqlite"
341
341
  if not database.is_file() or database.is_symlink():
342
342
  return {"status": "human_confirmation", "reason": "No Core review round exists"}
343
343
  db = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
@@ -366,7 +366,7 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
366
366
  index_generation = fixed.get("code_index_generation")
367
367
  if index_generation is not None:
368
368
  try:
369
- snapshot = read_json(safe_file(root, ".planning/code-index/SNAPSHOT.json"))
369
+ snapshot = read_json(safe_file(root, ".devflow/planning/code-index/SNAPSHOT.json"))
370
370
  if snapshot.get("generation") != index_generation:
371
371
  return {"status": "stale_evidence", "reason": "Code-index generation changed after review", "chain_id": result.get("chain_id")}
372
372
  except (OSError, ValueError, json.JSONDecodeError):
@@ -415,11 +415,11 @@ def review_markdown(result: dict) -> str:
415
415
 
416
416
  def render_review(root: Path, feature: str, contract_id: str) -> dict:
417
417
  root = root.resolve(strict=True)
418
- contract = read_json(safe_file(root, f".planning/contracts/{feature}/{contract_id}.json"))
418
+ contract = read_json(safe_file(root, f".devflow/planning/contracts/{feature}/{contract_id}.json"))
419
419
  path = next((item for item in contract.get("allowed_paths", []) if isinstance(item, str) and item.endswith("/REVIEW.md")), None)
420
420
  if not path:
421
421
  return {"status": "core_contract_conflict", "reason": "Core contract has no REVIEW.md output"}
422
- database = root / ".planning/review-runs/review-runs.sqlite"
422
+ database = root / ".devflow/planning/review-runs/review-runs.sqlite"
423
423
  if not database.is_file():
424
424
  return {"status": "human_confirmation", "reason": "No Core review round exists"}
425
425
  db = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
@@ -616,7 +616,7 @@ def run(root: Path, request: dict) -> dict:
616
616
  db.commit()
617
617
  return result
618
618
  if index_discovery.get("generation"):
619
- current_snapshot = root / ".planning" / "code-index" / "SNAPSHOT.json"
619
+ current_snapshot = root / ".devflow/planning" / "code-index" / "SNAPSHOT.json"
620
620
  if not current_snapshot.exists() or read_json(current_snapshot).get("generation") != index_discovery["generation"]:
621
621
  result = response("stale_evidence", chain_id, round_no, questions=["Code-index generation changed during review"])
622
622
  db.execute("INSERT INTO events(chain_id,status,detail_json) VALUES(?,?,?)", (chain_id, result["status"], canonical(result)))
@@ -645,7 +645,7 @@ def run(root: Path, request: dict) -> dict:
645
645
  db.commit()
646
646
  return result
647
647
  status = "terminated_p0" if round_no == 3 and summary["P0"] else ("findings" if open_findings else "clean")
648
- core_results = {rel: digest(safe_file(root, rel).read_bytes()) for rel in (f".planning/requirements/{target['feature']}/tests.json", f".planning/test-runs/{target['feature']}/acceptance-results.json")}
648
+ core_results = {rel: digest(safe_file(root, rel).read_bytes()) for rel in (f".devflow/planning/requirements/{target['feature']}/tests.json", f".devflow/planning/test-runs/{target['feature']}/acceptance-results.json")}
649
649
  result = response(status, chain_id, round_no, fixed_versions={"source": versions, "authority": accepted, "core_results": core_results, "change_plan": {"path": change_plan_path, "sha256": change_plan_hash, "declared_paths": sorted(declared_paths)}, "code_index_generation": index_discovery.get("generation")}, index_discovery=index_discovery, coverage={"covered": sorted(covered), "gaps": gaps, "index_gap": index_discovery.get("reason") if index_discovery["status"] != "located" else None}, findings=findings, risk_summary=summary, improvement_plan=[{"finding_id": f["finding_id"], "severity": f["severity"], "action": f["improvement"]} for f in sorted(open_findings, key=lambda x: x["severity"])], all_p0_resolved=summary["P0"] == 0, severity_source="independent_reviewer_core_evidence_bound", semantic_causality_verified=True, automatic_release_allowed=status == "clean", termination_scope="current_task_only" if status == "terminated_p0" else None, reviewer_task={key: binding[key] for key in ("agent", "feature", "contract_id", "task_call_id", "report_sha256")}, history=[{"round": r, "status": json.loads(raw)["status"]} for r, raw in db.execute("SELECT round,result_json FROM rounds WHERE chain_id=? ORDER BY round", (chain_id,))])
650
650
  db.execute("INSERT INTO reviewer_tasks(task_call_id,chain_id,round,report_sha256) VALUES(?,?,?,?)", (binding["task_call_id"], chain_id, round_no, binding["report_sha256"]))
651
651
  db.execute("INSERT INTO rounds(chain_id,round,result_json) VALUES(?,?,?)", (chain_id, round_no, canonical(result)))
@@ -14,8 +14,8 @@ require_relative "control_io"
14
14
 
15
15
  module RuntimeContextCollector
16
16
  SCHEMA_VERSION = 1
17
- HISTORY_DIR = File.join(".context", "runtime-context", "revisions")
18
- POINTER = File.join(".context", "runtime-context.json")
17
+ HISTORY_DIR = File.join(".devflow/context", "runtime-context", "revisions")
18
+ POINTER = File.join(".devflow/context", "runtime-context.json")
19
19
  EXTRACTORS = {
20
20
  "package.json" => :extract_package_json,
21
21
  "requirements.txt" => :extract_requirements_txt,
@@ -170,7 +170,7 @@ module RuntimeContextCollector
170
170
  history = File.join(root, HISTORY_DIR, "#{revision}.json")
171
171
  DevflowControlIO.atomic_create(history, JSON.pretty_generate(snapshot) + "\n")
172
172
  DevflowControlIO.atomic_write(File.join(root, POINTER), JSON.pretty_generate({ "current_revision" => revision, "path" => history.sub("#{root}/", "") }) + "\n")
173
- DevflowControlIO.append_audit(File.join(root, ".context", "runtime-context", "audit.jsonl"), {
173
+ DevflowControlIO.append_audit(File.join(root, ".devflow/context", "runtime-context", "audit.jsonl"), {
174
174
  "event" => "snapshot_collected", "snapshot_revision" => revision,
175
175
  "repository_revision" => repository_revision, "coverage_status" => coverage_status
176
176
  })
@@ -69,7 +69,7 @@ def lease_expiry(seconds)
69
69
  end
70
70
 
71
71
  root = Dir.pwd
72
- state_path, = DevflowControlIO.resolve_control_path(root, ".planning/STATE.md", :state)
72
+ state_path, = DevflowControlIO.resolve_control_path(root, ".devflow/planning/STATE.md", :state)
73
73
  result = catch(:transition_done) do
74
74
  lock = DevflowControlIO.acquire_project_lock(root)
75
75
  begin
@@ -129,7 +129,7 @@ result = catch(:transition_done) do
129
129
  throw :transition_done, result
130
130
  end
131
131
  rollover_id = "ROL-#{SecureRandom.uuid}"
132
- relative_path = ".planning/handoffs/#{state.fetch("current_feature")}/#{rollover_id}.json"
132
+ relative_path = ".devflow/planning/handoffs/#{state.fetch("current_feature")}/#{rollover_id}.json"
133
133
  absolute_path, = DevflowControlIO.resolve_control_path(root, relative_path, :handoff)
134
134
  payload = {
135
135
  "schema_version" => 1,
@@ -144,9 +144,9 @@ result = catch(:transition_done) do
144
144
  "status" => state["status"], "completed_steps" => state["completed_steps"], "pending_steps" => state["pending_steps"]
145
145
  },
146
146
  "references" => {
147
- "state_path" => ".planning/STATE.md",
147
+ "state_path" => ".devflow/planning/STATE.md",
148
148
  "workflow_path" => state["workflow_config"],
149
- "artifact_registry" => ".planning/artifacts/index.yaml"
149
+ "artifact_registry" => ".devflow/planning/artifacts/index.yaml"
150
150
  }
151
151
  }
152
152
  serialized = JSON.generate(payload) + "\n"
@@ -17,9 +17,9 @@ require_relative "control_io"
17
17
  module StaticRuntimeContextCollector
18
18
  SCHEMA_VERSION = 2
19
19
  COLLECTOR_VERSION = "static-runtime-context-v2.1"
20
- ROOT_DIR = File.join(".context", "static-runtime-context")
20
+ ROOT_DIR = File.join(".devflow/context", "static-runtime-context")
21
21
  HISTORY_DIR = File.join(ROOT_DIR, "revisions")
22
- POINTER = ".context/static-runtime-context.json"
22
+ POINTER = ".devflow/context/static-runtime-context.json"
23
23
  AUDIT_PATH = File.join(ROOT_DIR, "audit.jsonl")
24
24
  MAX_COMPOSE_BYTES = 1_048_576
25
25
  EXCLUDED_ROOTS = %w[node_modules vendor dist build .git].freeze
@@ -11,7 +11,7 @@ require_relative "control_io"
11
11
  require_relative "phase_ownership"
12
12
 
13
13
  options = {
14
- state: ".planning/STATE.md",
14
+ state: ".devflow/planning/STATE.md",
15
15
  workflow: nil,
16
16
  output: nil,
17
17
  write: false,
@@ -72,10 +72,10 @@ unless ownership["ok"]
72
72
  puts JSON.pretty_generate(ownership.merge("written" => false))
73
73
  exit 0
74
74
  end
75
- workflow_source = options[:workflow] || state["workflow_config"] || ".planning/workflows/#{state.fetch("current_flow")}.yaml"
75
+ workflow_source = options[:workflow] || state["workflow_config"] || ".devflow/planning/workflows/#{state.fetch("current_flow")}.yaml"
76
76
  workflow_path, = DevflowControlIO.resolve_control_path(root, workflow_source, :workflow)
77
77
  workflow = load_yaml_file(workflow_path)
78
- registry_source = options[:output] || workflow.dig("artifact_registry", "source") || ".planning/artifacts/index.yaml"
78
+ registry_source = options[:output] || workflow.dig("artifact_registry", "source") || ".devflow/planning/artifacts/index.yaml"
79
79
  existing_registry_path, registry_path = DevflowControlIO.resolve_control_path(root, registry_source, :registry)
80
80
  existing_by_path = {}
81
81
  if options[:preserve] && File.exist?(existing_registry_path)
@@ -112,7 +112,7 @@ end
112
112
 
113
113
  def questions_registry_entry(root, state, existing_by_path)
114
114
  feature = state.fetch("current_feature", "").to_s
115
- path = ".planning/features/#{feature}/questions.yaml"
115
+ path = ".devflow/planning/features/#{feature}/questions.yaml"
116
116
  absolute, = DevflowControlIO.resolve_control_path(root, path, :artifact)
117
117
  exists = File.exist?(absolute)
118
118
  entry = {
@@ -180,7 +180,7 @@ artifacts = collect_outputs(workflow).map do |step, output|
180
180
  }.reject { |_, value| value.nil? || value == [] }
181
181
  end
182
182
 
183
- questions_path = ".planning/features/#{state.fetch("current_feature", "")}/questions.yaml"
183
+ questions_path = ".devflow/planning/features/#{state.fetch("current_feature", "")}/questions.yaml"
184
184
  questions_entry = questions_registry_entry(root, state, existing_by_path)
185
185
  question_index = artifacts.index { |artifact| artifact["path"] == questions_path }
186
186
  if question_index