okstra 0.209.3 → 0.209.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.209.3",
3
+ "version": "0.209.4",
4
4
  "description": "Host-aware multi-provider cross-verification orchestrator runtime and agent skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.209.3",
3
- "builtAt": "2026-10-05T06:23:58.308Z",
2
+ "package": "0.209.4",
3
+ "builtAt": "2026-10-05T06:38:59.441Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -313,6 +313,23 @@ def _complete_request(
313
313
  return "\n".join(lines) + "\n"
314
314
 
315
315
 
316
+ def canonical_request_path(planning_seq: str, item_id: str) -> str:
317
+ return f"design-prep-requests/design-prep-request-{planning_seq}-{item_id}.md"
318
+
319
+
320
+ def canonicalize_request_paths(data: Mapping[str, Any], data_path: Path) -> None:
321
+ """Name each open item's request by this report's planning seq.
322
+
323
+ The detector snapshot cannot know the report seq and names requests by stage
324
+ number, so a second planning run of the same task pointed its request at the
325
+ first run's file and materialization refused to overwrite it.
326
+ """
327
+ planning_seq = _planning_seq(Path(data_path))
328
+ for item in _design_preparation_items(data):
329
+ if isinstance(item, dict) and "requestPath" in item and isinstance(item.get("id"), str):
330
+ item["requestPath"] = canonical_request_path(planning_seq, item["id"])
331
+
332
+
316
333
  def _request_target(
317
334
  *,
318
335
  data_path: Path,
@@ -322,10 +339,7 @@ def _request_target(
322
339
  item_id = item.get("id")
323
340
  if not isinstance(item_id, str) or not item_id:
324
341
  raise DesignPrepError("design preparation item id must be a non-empty string")
325
- expected_relative = (
326
- "design-prep-requests/"
327
- f"design-prep-request-{planning_seq}-{item_id}.md"
328
- )
342
+ expected_relative = canonical_request_path(planning_seq, item_id)
329
343
  request_dir = data_path.parent.parent / "design-prep-requests"
330
344
  recorded = item.get("requestPath")
331
345
  if recorded == expected_relative:
@@ -26,7 +26,11 @@ from .report_synthesis_packet import (
26
26
  )
27
27
  from .conformance import strip_stage_declaration_label
28
28
  from .coverage_census import census_warning_rows, read_census_state
29
- from .design_prep import DesignPrepError, materialize_design_prep_requests
29
+ from .design_prep import (
30
+ DesignPrepError,
31
+ canonicalize_request_paths,
32
+ materialize_design_prep_requests,
33
+ )
30
34
  from .phases.implementation_option_selection.validation import validate_blocked_answer_channel
31
35
  from .phases.technical_verification.validation import validate_technical_verification_report
32
36
  from .report_routing import technical_verification_routing_errors
@@ -830,6 +834,16 @@ def assemble_report(
830
834
  if input_issues:
831
835
  raise ReportAssemblyError(tuple(input_issues))
832
836
  data = _compose(project_root, manifest_path, manifest, inputs, schema)
837
+ value = manifest.get("expectedReportRecordPath")
838
+ if not isinstance(value, str) or not value:
839
+ _fail("orchestrator", manifest_path, "expectedReportRecordPath", "required")
840
+ target = Path(value)
841
+ target = target if target.is_absolute() else project_root / target
842
+ if manifest.get("taskType") == "implementation-planning":
843
+ try:
844
+ canonicalize_request_paths(data, target)
845
+ except DesignPrepError as exc:
846
+ _fail("orchestrator", target, "designPreparation", str(exc))
833
847
  errors = validate(data, schema)
834
848
  path_errors = planned_path_declaration_errors(data)
835
849
  if path_errors:
@@ -840,11 +854,6 @@ def assemble_report(
840
854
  direction_errors = selected_direction_plan_errors(
841
855
  data, project_root, manifest
842
856
  )
843
- value = manifest.get("expectedReportRecordPath")
844
- if not isinstance(value, str) or not value:
845
- _fail("orchestrator", manifest_path, "expectedReportRecordPath", "required")
846
- target = Path(value)
847
- target = target if target.is_absolute() else project_root / target
848
857
  verification_errors = validate_technical_verification_report(data, target, project_root)
849
858
  verification_errors.extend(technical_verification_routing_errors(data))
850
859
  if verification_errors: