diff --git a/docs/doctoring/contextual-orchestrator-vendored-sidecar.md b/docs/doctoring/contextual-orchestrator-vendored-sidecar.md index ff659cfcad..4d098e6f32 100644 --- a/docs/doctoring/contextual-orchestrator-vendored-sidecar.md +++ b/docs/doctoring/contextual-orchestrator-vendored-sidecar.md @@ -74,3 +74,17 @@ training (OpenRouter's own stance). Evidence sources: `tests/test_pr_review_autofix_writer_security_contract.py`, `tests/test_noema_review_gate.py`, `docs/doctoring/noema-orchestrator-free-zdr.md`. + +## 2026-08-28 runtime correction + +The first post-merge Strix execution (`33139957477`) failed before serving: the +pinned orchestrator's `load_agents()` indexes the top-level `agents` field, but +the launcher persisted only the list value. Follow-up PR [#1370](https://github.com/ContextualWisdomLab/.github/pull/1370) +wraps both the launcher output and the standalone policy builder output in the +loader-compatible `{"agents": [...]}` envelope. The regression is covered by +`tests/test_contextual_orchestrator_review_policy.py` and the sidecar contract; +the full local suite passed with `1689 passed, 1 skipped, 16 subtests passed`. + +The PR-target Noema check still runs the trusted base copy until this trusted +workflow change is merged, so its reproduction of the old error is retained as +bootstrap evidence rather than treated as a current-head runtime result. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a6c8546502..28ae1a9ba2 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -234,9 +234,37 @@ flowchart LR `zdr_policy.py`, `contextual_orchestrator_review_policy.py`, `contextual_orchestrator_review_launcher.py`; records `docs/adr/0003-…`, `docs/doctoring/contextual-orchestrator-vendored-sidecar.md`. -- Remaining (follow-up loops): read-only dispatch pool, `noema-review.yml`, - and `strix.yml` still use pinned direct-provider pools; ZDR feed integration - in the standard opencode pool and runner-side egress attestation per stage. +- At the time of this 2026-08-27 snapshot, the remaining follow-up was the + read-only dispatch pool, `noema-review.yml`, and `strix.yml` migration. This + historical observation is superseded by the current-main evidence below. + +## 2026-08-28 current-main routing and runtime recheck + +- Current protected-main candidate is `f8823a544c3c4c046977f8511f683e85f83eb496`, + the merge commit for #1364. #1360 is merged at + `17052a7ca3c16db90932a4d6036b43165ddee418`. +- The current Required OpenCode dispatch, `noema-review.yml`, `strix.yml`, + and write-capable `pr-review-autofix.yml` all provision the pinned + `contextual-orchestrator` sidecar. Their model route is the + `contextual-orchestrator/orchestrator/free` gateway, with the five provider + secrets entering the sidecar KV and model discovery performed there. No + `COPILOT_GITHUB_TOKEN` route is present. +- #1364 was merged by `seonghobae` while its terminal review decision remained + `CHANGES_REQUESTED`; this is an observed merge event, not protected-main + governance evidence. The required branch checks still include + `noema-review` and `opencode-review`. +- Post-merge Strix run `33139957477` exposed a real sidecar runtime defect: + `contextual_orchestrator.orchestrator.load_agents()` requires an + `{"agents": [...]}` catalog envelope, while the launcher wrote a bare list. + Follow-up #1370 fixes the launcher and the standalone policy catalog writer + in commit `861463c11a7ca8b1f9179073e2a3db9eba5aa5ab`; its current head is + `38e0307c655823a1e474b29aae89f8cfcb1edbc0`. Focused tests and the full local + suite pass (`1689 passed, 1 skipped, 16 subtests passed`). +- #1370 remains open and blocked against main `f8823a5`. Its PR-target Noema + run `33140830199` executes the trusted base launcher and reproduces the + pre-fix bare-list error; its `opencode-review` check fails closed because no + current-head OpenCode verdict exists. These are bootstrap evidence gaps, + not proof that the #1370 catalog-envelope patch fails. ## 5. 실행 루프와 고객의 다음 행동 diff --git a/scripts/ci/contextual_orchestrator_review_launcher.py b/scripts/ci/contextual_orchestrator_review_launcher.py index cfb158d737..e8f238ad24 100644 --- a/scripts/ci/contextual_orchestrator_review_launcher.py +++ b/scripts/ci/contextual_orchestrator_review_launcher.py @@ -145,7 +145,7 @@ def main(argv: list[str] | None = None) -> int: require_zdr=args.require_zdr, ) Path(args.catalog_out).write_text( - json.dumps(result["agents"], indent=2) + "\n", encoding="utf-8" + json.dumps({"agents": result["agents"]}, indent=2) + "\n", encoding="utf-8" ) Path(args.report_out).write_text( json.dumps(result["report"], indent=2) + "\n", encoding="utf-8" @@ -163,4 +163,4 @@ def main(argv: list[str] | None = None) -> int: if __name__ == "__main__": # pragma: no cover - raise SystemExit(main()) \ No newline at end of file + raise SystemExit(main()) diff --git a/scripts/ci/contextual_orchestrator_review_policy.py b/scripts/ci/contextual_orchestrator_review_policy.py index dfadf62976..66c6f305b0 100644 --- a/scripts/ci/contextual_orchestrator_review_policy.py +++ b/scripts/ci/contextual_orchestrator_review_policy.py @@ -337,7 +337,9 @@ def build_catalog_from_paths( zdr_endpoints=zdr_endpoints, require_zdr=require_zdr, ) - Path(out_path).write_text(json.dumps(result["agents"], indent=2) + "\n", encoding="utf-8") + Path(out_path).write_text( + json.dumps({"agents": result["agents"]}, indent=2) + "\n", encoding="utf-8" + ) Path(report_path).write_text(json.dumps(result["report"], indent=2) + "\n", encoding="utf-8") return result @@ -384,4 +386,4 @@ def main(argv: list[str] | None = None) -> int: if __name__ == "__main__": # pragma: no cover - raise SystemExit(main()) \ No newline at end of file + raise SystemExit(main()) diff --git a/tests/test_contextual_orchestrator_review_policy.py b/tests/test_contextual_orchestrator_review_policy.py index 30db360d5e..75a33cd4b6 100644 --- a/tests/test_contextual_orchestrator_review_policy.py +++ b/tests/test_contextual_orchestrator_review_policy.py @@ -319,7 +319,7 @@ def test_build_catalog_from_paths_writes_both_files(tmp_path) -> None: ) assert catalog.exists() assert report.exists() - assert result["agents"] == json.loads(catalog.read_text(encoding="utf-8")) + assert {"agents": result["agents"]} == json.loads(catalog.read_text(encoding="utf-8")) assert result["report"] == json.loads(report.read_text(encoding="utf-8")) diff --git a/tests/test_contextual_orchestrator_review_sidecar_contract.py b/tests/test_contextual_orchestrator_review_sidecar_contract.py index 279cf58d79..350b8383fd 100644 --- a/tests/test_contextual_orchestrator_review_sidecar_contract.py +++ b/tests/test_contextual_orchestrator_review_sidecar_contract.py @@ -110,6 +110,13 @@ def test_launcher_uses_orchestrator_discovery_and_free_pool() -> None: assert "from scripts.ci import zdr_policy" in text +def test_launcher_wraps_catalog_for_vendored_load_agents() -> None: + """Persist the catalog envelope expected by the pinned orchestrator loader.""" + text = _read(LAUNCHER) + assert 'json.dumps({"agents": result["agents"]}' in text + assert 'json.dumps(result["agents"]' not in text + + def test_launcher_requires_gateway_token_and_a_provider_credential() -> None: """The sidecar never boots without an auth token and a provider credential.""" text = _read(LAUNCHER)