From 483ea1de1cfe70532e7242ed6a1c7cc30ddcea05 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 21:52:32 +0900 Subject: [PATCH 1/7] chore: stage adaptive orchestrator consumer migration --- .../apply_adaptive_orchestrator_default.py | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 scripts/apply_adaptive_orchestrator_default.py diff --git a/scripts/apply_adaptive_orchestrator_default.py b/scripts/apply_adaptive_orchestrator_default.py new file mode 100644 index 000000000..77e83cccd --- /dev/null +++ b/scripts/apply_adaptive_orchestrator_default.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +"""Migrate active contextual-orchestrator consumers from route to auto.""" +from __future__ import annotations + +import os +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +EXPECTED_BRANCH = "agent/adaptive-orchestrator-default" +ACTIVE_CLIENTS = ( + "lineageweave/post_summary.py", + "lineageweave/post_evaluation.py", + "lineageweave/keyman_extraction.py", + "lineageweave/commitment_extraction.py", + "lineageweave/post_chat.py", + "lineageweave/entity_relationship_classification.py", +) + + +def replace_once(text: str, old: str, new: str, label: str) -> str: + """Replace exactly one expected repository fragment.""" + count = text.count(old) + if count != 1: + raise RuntimeError(f"{label}: expected one match, found {count}") + return text.replace(old, new, 1) + + +def main() -> None: + """Patch code and add policy evidence.""" + branch = os.environ.get("GITHUB_REF_NAME", EXPECTED_BRANCH) + if branch != EXPECTED_BRANCH: + raise RuntimeError(f"refusing to mutate unexpected branch: {branch}") + + for relative in ACTIVE_CLIENTS: + path = ROOT / relative + text = path.read_text(encoding="utf-8") + original = text + text = text.replace('"mode": "route"', '"mode": "auto"') + text = text.replace('mode="route"', 'mode="auto"') + text = text.replace('mode: str = "route"', 'mode: str = "auto"') + if text == original: + raise RuntimeError(f"{relative}: expected a route default to migrate") + path.write_text(text, encoding="utf-8") + + keyman_path = ROOT / "lineageweave" / "keyman_extraction.py" + keyman = keyman_path.read_text(encoding="utf-8") + keyman = replace_once( + keyman, + '''that benefits from the orchestrator's reasoning-effort allocation, not a +single confidence number, so it uses ``mode="auto"`` (one worker call) at +a ``"medium"`` reasoning effort by default rather than ``verify``'s +worker-plus-checker pattern, which is reserved for adjudication's binary +judgment calls. +''', + '''that benefits from the orchestrator's task-sensitive allocation of model, +reasoning effort, and workflow depth. It therefore uses ``mode="auto"`` at +a ``"medium"`` reasoning effort by default; contextual-orchestrator may use +a single worker or escalate to verification/conducted work when the detected +quality requirement justifies the additional cost. +''', + "keyman policy explanation", + ) + keyman_path.write_text(keyman, encoding="utf-8") + + changelog_path = ROOT / "CHANGELOG.md" + changelog = changelog_path.read_text(encoding="utf-8") + changelog = replace_once( + changelog, + "## [0.71.0] - 2026-08-14\n", + "## [Unreleased]\n\n### Changed\n\n" + "- Active contextual-orchestrator clients now request `mode=\"auto\"` rather than forcing a one-model route. The orchestrator owns the minimum-cost route, verification, or conducted workflow that satisfies the detected quality requirement; explicit modes remain available for controlled experiments and operator overrides.\n\n" + "## [0.71.0] - 2026-08-14\n", + "changelog", + ) + changelog_path.write_text(changelog, encoding="utf-8") + + test_path = ROOT / "tests" / "test_contextual_orchestrator_default_policy.py" + if test_path.exists(): + raise RuntimeError(f"refusing to replace existing policy test: {test_path}") + test_path.write_text(POLICY_TEST, encoding="utf-8") + + adr_path = ROOT / "docs" / "adr" / "0005-adaptive-orchestrator-default.md" + if adr_path.exists(): + raise RuntimeError(f"refusing to replace existing ADR: {adr_path}") + adr_path.write_text(ADR, encoding="utf-8") + + +POLICY_TEST = '''"""Contract tests for adaptive contextual-orchestrator consumer defaults.""" +from __future__ import annotations + +from pathlib import Path +import unittest + +ROOT = Path(__file__).resolve().parents[1] +ACTIVE_CLIENTS = ( + "lineageweave/post_summary.py", + "lineageweave/post_evaluation.py", + "lineageweave/keyman_extraction.py", + "lineageweave/commitment_extraction.py", + "lineageweave/post_chat.py", + "lineageweave/entity_relationship_classification.py", +) + + +class AdaptiveOrchestratorDefaultTest(unittest.TestCase): + """Protect production clients from regressing to forced one-model routing.""" + + def test_active_clients_use_auto_and_never_force_route(self) -> None: + for relative in ACTIVE_CLIENTS: + source = (ROOT / relative).read_text(encoding="utf-8") + with self.subTest(path=relative): + self.assertNotIn('"mode": "route"', source) + self.assertNotIn('mode="route"', source) + self.assertNotIn('mode: str = "route"', source) + self.assertTrue( + '"mode": "auto"' in source + or 'mode="auto"' in source + or 'mode: str = "auto"' in source + ) + + def test_high_stakes_adjudication_retains_explicit_checked_override(self) -> None: + source = (ROOT / "lineageweave/adjudication_client.py").read_text(encoding="utf-8") + self.assertIn('"mode": "verify"', source) + + +if __name__ == "__main__": + unittest.main() +''' + +ADR = '''# ADR-0005: Adaptive contextual-orchestrator mode is the consumer default + +- Status: Accepted +- Date: 2026-08-15 + +## Context + +LineageWeave previously forced `mode="route"` in summarization, post evaluation, +Keyman extraction, commitment extraction, post chat, and relationship +classification. That made the consumer choose a single model before +contextual-orchestrator could evaluate task difficulty, capability fit, +verification need, and known model price. + +Research on adaptive orchestration and cost-aware reliability shows that no fixed +model/workflow/budget choice dominates for all requests. Dynamic scaffolding and +query-level cost allocation are therefore responsibilities of the orchestration +plane, not of each domain client. + +## Decision + +Active general-purpose clients request `mode="auto"`. + +- contextual-orchestrator selects the quality-sufficient route, bounded + verification, or conducted workflow and then minimizes known cost inside the + selected capability tier; +- LineageWeave continues to own prompts, schemas, strict parsing, domain evidence, + and failure semantics; +- the low-volume lineage adjudication channel retains the explicit `verify` + override because an independently checked verdict is part of that domain + contract, not an accidental routing default; +- explicit modes remain permitted for ablation, regression comparison, and + emergency operator policy, but they are not ordinary production defaults. + +## Consequences + +Trace width is no longer a stable consumer assumption for `auto` requests. +Telemetry and tests must record the requested policy and actual trace. Cost +claims require configured price evidence; an unpriced model is never treated as +free. + +## References + +Omidvar, H., & Akhlaghi, V. (2026). *A communication-theoretic framework for LLM agents: Cost-aware adaptive reliability* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2605.09121 + +Tang, Y., Cetin, E., Xu, J., Sun, Q., Nielsen, S., Richard, V., Goda, H., Tymchenko, I., Nguyen, N., Lee, H., Ashiga, M., Kotyan, S., Kuroki, S., & Clanuwat, T. (2026). *Sakana Fugu technical report* [Technical report]. arXiv. https://doi.org/10.48550/arXiv.2606.21228 +''' + +if __name__ == "__main__": + main() From 095f20ba8f605330426a436227f4b7311cddd6a9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 21:52:49 +0900 Subject: [PATCH 2/7] ci: apply and verify adaptive consumer defaults --- .../apply-adaptive-orchestrator-default.yml | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/workflows/apply-adaptive-orchestrator-default.yml diff --git a/.github/workflows/apply-adaptive-orchestrator-default.yml b/.github/workflows/apply-adaptive-orchestrator-default.yml new file mode 100644 index 000000000..2b97bcabf --- /dev/null +++ b/.github/workflows/apply-adaptive-orchestrator-default.yml @@ -0,0 +1,56 @@ +name: Apply adaptive contextual-orchestrator consumer default + +on: + push: + branches: + - agent/adaptive-orchestrator-default + paths: + - scripts/apply_adaptive_orchestrator_default.py + - .github/workflows/apply-adaptive-orchestrator-default.yml + +permissions: + contents: write + +concurrency: + group: apply-adaptive-orchestrator-default-${{ github.ref }} + cancel-in-progress: false + +jobs: + apply-and-verify: + runs-on: ubuntu-latest + steps: + - name: Checkout exact branch head + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + fetch-depth: 0 + persist-credentials: true + + - name: Set up Python + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Apply bounded source transformation + run: python scripts/apply_adaptive_orchestrator_default.py + + - name: Compile production and contract test sources + run: python -m compileall -q lineageweave tests/test_contextual_orchestrator_default_policy.py + + - name: Run dependency-free policy contract + run: python tests/test_contextual_orchestrator_default_policy.py + + - name: Inspect patch + run: git diff --check + + - name: Publish verified implementation commit + env: + TARGET_BRANCH: agent/adaptive-orchestrator-default + run: | + rm scripts/apply_adaptive_orchestrator_default.py + rm .github/workflows/apply-adaptive-orchestrator-default.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add --all + git diff --cached --check + git commit -m "fix(ai): default consumers to adaptive orchestration" + git push origin "HEAD:${TARGET_BRANCH}" From 452581f6d7c61860f72c70ad7a0890a5974248f5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 14:31:20 +0000 Subject: [PATCH 3/7] fix(ai): default consumers to adaptive orchestration --- .../apply-adaptive-orchestrator-default.yml | 56 ------ CHANGELOG.md | 6 + .../adr/0005-adaptive-orchestrator-default.md | 45 +++++ lineageweave/commitment_extraction.py | 4 +- .../entity_relationship_classification.py | 4 +- lineageweave/keyman_extraction.py | 14 +- lineageweave/post_chat.py | 2 +- lineageweave/post_evaluation.py | 4 +- lineageweave/post_summary.py | 4 +- .../apply_adaptive_orchestrator_default.py | 178 ------------------ ..._contextual_orchestrator_default_policy.py | 40 ++++ 11 files changed, 107 insertions(+), 250 deletions(-) delete mode 100644 .github/workflows/apply-adaptive-orchestrator-default.yml create mode 100644 docs/adr/0005-adaptive-orchestrator-default.md delete mode 100644 scripts/apply_adaptive_orchestrator_default.py create mode 100644 tests/test_contextual_orchestrator_default_policy.py diff --git a/.github/workflows/apply-adaptive-orchestrator-default.yml b/.github/workflows/apply-adaptive-orchestrator-default.yml deleted file mode 100644 index 2b97bcabf..000000000 --- a/.github/workflows/apply-adaptive-orchestrator-default.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Apply adaptive contextual-orchestrator consumer default - -on: - push: - branches: - - agent/adaptive-orchestrator-default - paths: - - scripts/apply_adaptive_orchestrator_default.py - - .github/workflows/apply-adaptive-orchestrator-default.yml - -permissions: - contents: write - -concurrency: - group: apply-adaptive-orchestrator-default-${{ github.ref }} - cancel-in-progress: false - -jobs: - apply-and-verify: - runs-on: ubuntu-latest - steps: - - name: Checkout exact branch head - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - fetch-depth: 0 - persist-credentials: true - - - name: Set up Python - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # actions/setup-python@v6 - with: - python-version: "3.12" - - - name: Apply bounded source transformation - run: python scripts/apply_adaptive_orchestrator_default.py - - - name: Compile production and contract test sources - run: python -m compileall -q lineageweave tests/test_contextual_orchestrator_default_policy.py - - - name: Run dependency-free policy contract - run: python tests/test_contextual_orchestrator_default_policy.py - - - name: Inspect patch - run: git diff --check - - - name: Publish verified implementation commit - env: - TARGET_BRANCH: agent/adaptive-orchestrator-default - run: | - rm scripts/apply_adaptive_orchestrator_default.py - rm .github/workflows/apply-adaptive-orchestrator-default.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add --all - git diff --cached --check - git commit -m "fix(ai): default consumers to adaptive orchestration" - git push origin "HEAD:${TARGET_BRANCH}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 0096828a2..f52171bda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Changed + +- Active contextual-orchestrator clients now request `mode="auto"` rather than forcing a one-model route. The orchestrator owns the minimum-cost route, verification, or conducted workflow that satisfies the detected quality requirement; explicit modes remain available for controlled experiments and operator overrides. + ## [0.71.0] - 2026-08-14 ### Added diff --git a/docs/adr/0005-adaptive-orchestrator-default.md b/docs/adr/0005-adaptive-orchestrator-default.md new file mode 100644 index 000000000..c64585f8d --- /dev/null +++ b/docs/adr/0005-adaptive-orchestrator-default.md @@ -0,0 +1,45 @@ +# ADR-0005: Adaptive contextual-orchestrator mode is the consumer default + +- Status: Accepted +- Date: 2026-08-15 + +## Context + +LineageWeave previously forced `mode="route"` in summarization, post evaluation, +Keyman extraction, commitment extraction, post chat, and relationship +classification. That made the consumer choose a single model before +contextual-orchestrator could evaluate task difficulty, capability fit, +verification need, and known model price. + +Research on adaptive orchestration and cost-aware reliability shows that no fixed +model/workflow/budget choice dominates for all requests. Dynamic scaffolding and +query-level cost allocation are therefore responsibilities of the orchestration +plane, not of each domain client. + +## Decision + +Active general-purpose clients request `mode="auto"`. + +- contextual-orchestrator selects the quality-sufficient route, bounded + verification, or conducted workflow and then minimizes known cost inside the + selected capability tier; +- LineageWeave continues to own prompts, schemas, strict parsing, domain evidence, + and failure semantics; +- the low-volume lineage adjudication channel retains the explicit `verify` + override because an independently checked verdict is part of that domain + contract, not an accidental routing default; +- explicit modes remain permitted for ablation, regression comparison, and + emergency operator policy, but they are not ordinary production defaults. + +## Consequences + +Trace width is no longer a stable consumer assumption for `auto` requests. +Telemetry and tests must record the requested policy and actual trace. Cost +claims require configured price evidence; an unpriced model is never treated as +free. + +## References + +Omidvar, H., & Akhlaghi, V. (2026). *A communication-theoretic framework for LLM agents: Cost-aware adaptive reliability* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2605.09121 + +Tang, Y., Cetin, E., Xu, J., Sun, Q., Nielsen, S., Richard, V., Goda, H., Tymchenko, I., Nguyen, N., Lee, H., Ashiga, M., Kotyan, S., Kuroki, S., & Clanuwat, T. (2026). *Sakana Fugu technical report* [Technical report]. arXiv. https://doi.org/10.48550/arXiv.2606.21228 diff --git a/lineageweave/commitment_extraction.py b/lineageweave/commitment_extraction.py index 341eaa0c8..459376617 100644 --- a/lineageweave/commitment_extraction.py +++ b/lineageweave/commitment_extraction.py @@ -136,7 +136,7 @@ def parse_commitment_response(content: str) -> CustomerCommitment | None: class ContextualOrchestratorCommitmentExtractionClient: - """Calls ``POST {base_url}/v1/chat/completions`` with ``mode="route"``.""" + """Calls ``POST {base_url}/v1/chat/completions`` with ``mode="auto"``.""" available = True @@ -156,7 +156,7 @@ def extract(self, post_title: str, post_body: str, reference_date: str) -> Custo f"{self._base_url}/v1/chat/completions", { "messages": [{"role": "user", "content": prompt}], - "mode": "route", + "mode": "auto", "reasoning_effort": self._reasoning_effort, }, headers={"authorization": f"Bearer {self._api_key}"}, diff --git a/lineageweave/entity_relationship_classification.py b/lineageweave/entity_relationship_classification.py index d1a2056ca..ad23e7d9a 100644 --- a/lineageweave/entity_relationship_classification.py +++ b/lineageweave/entity_relationship_classification.py @@ -157,7 +157,7 @@ def parse_classification_response( class ContextualOrchestratorEntityRelationshipClient: - """Calls ``POST {base_url}/v1/chat/completions`` with ``mode="route"``.""" + """Calls ``POST {base_url}/v1/chat/completions`` with ``mode="auto"``.""" available = True @@ -183,7 +183,7 @@ def classify( f"{self._base_url}/v1/chat/completions", { "messages": [{"role": "user", "content": prompt}], - "mode": "route", + "mode": "auto", "reasoning_effort": self._reasoning_effort, }, headers={"authorization": f"Bearer {self._api_key}"}, diff --git a/lineageweave/keyman_extraction.py b/lineageweave/keyman_extraction.py index d7e8de952..d202de9bd 100644 --- a/lineageweave/keyman_extraction.py +++ b/lineageweave/keyman_extraction.py @@ -10,11 +10,11 @@ :class:`ContextualOrchestratorKeymanExtractionClient` calls a running contextual-orchestrator instance -- never a raw LLM API directly, per AGENTS.md -- because Keyman identification is a structured-extraction task -that benefits from the orchestrator's reasoning-effort allocation, not a -single confidence number, so it uses ``mode="route"`` (one worker call) at -a ``"medium"`` reasoning effort by default rather than ``verify``'s -worker-plus-checker pattern, which is reserved for adjudication's binary -judgment calls. +that benefits from the orchestrator's task-sensitive allocation of model, +reasoning effort, and workflow depth. It therefore uses ``mode="auto"`` at +a ``"medium"`` reasoning effort by default; contextual-orchestrator may use +a single worker or escalate to verification/conducted work when the detected +quality requirement justifies the additional cost. """ from __future__ import annotations @@ -133,7 +133,7 @@ def parse_keyman_response(content: str) -> list[PersonMention]: class ContextualOrchestratorKeymanExtractionClient: - """Calls ``POST {base_url}/v1/chat/completions`` with ``mode="route"``.""" + """Calls ``POST {base_url}/v1/chat/completions`` with ``mode="auto"``.""" available = True @@ -151,7 +151,7 @@ def extract(self, post_title: str, post_body: str) -> list[PersonMention]: f"{self._base_url}/v1/chat/completions", { "messages": [{"role": "user", "content": prompt}], - "mode": "route", + "mode": "auto", "reasoning_effort": self._reasoning_effort, }, headers={"authorization": f"Bearer {self._api_key}"}, diff --git a/lineageweave/post_chat.py b/lineageweave/post_chat.py index 7ec67e943..d23624bc1 100644 --- a/lineageweave/post_chat.py +++ b/lineageweave/post_chat.py @@ -187,7 +187,7 @@ class ContextualOrchestratorPostChatClient: ``mode="verify"`` exists for (one worker call plus one checked verifier judgment), same reasoning ``adjudication_client`` already uses, not ``keyman_extraction``/``entity_relationship_classification``'s - single-pass ``mode="route"`` structured extraction. + single-pass ``mode="auto"`` structured extraction. """ available = True diff --git a/lineageweave/post_evaluation.py b/lineageweave/post_evaluation.py index 09ce21fd2..2d3be6291 100644 --- a/lineageweave/post_evaluation.py +++ b/lineageweave/post_evaluation.py @@ -85,7 +85,7 @@ def __init__(self, base_url: str, api_key: str, *, timeout: float = 60.0) -> Non self._api_key = api_key self._timeout = timeout - def complete(self, messages: list[dict[str, Any]], mode: str = "route") -> dict[str, Any]: + def complete(self, messages: list[dict[str, Any]], mode: str = "auto") -> dict[str, Any]: body = post_json( f"{self._base_url}/v1/chat/completions", {"messages": messages, "mode": mode, "reasoning_effort": "medium"}, @@ -107,7 +107,7 @@ class ContextualOrchestratorPostEvaluationClient: def __init__(self, base_url: str, api_key: str, *, timeout: float = 60.0) -> None: self._judge = ContextualOrchestratorJudge( _OrchestratorCompleteAdapter(base_url, api_key, timeout=timeout), - mode="route", + mode="auto", ) def evaluate(self, post_title: str, post_body: str) -> LLMJudgeResult: diff --git a/lineageweave/post_summary.py b/lineageweave/post_summary.py index 4974268c2..eac051fda 100644 --- a/lineageweave/post_summary.py +++ b/lineageweave/post_summary.py @@ -152,7 +152,7 @@ def parse_summary_response(content: str) -> PostSummary | None: class ContextualOrchestratorPostSummaryClient: - """Calls ``POST {base_url}/v1/chat/completions`` with ``mode="route"``.""" + """Calls ``POST {base_url}/v1/chat/completions`` with ``mode="auto"``.""" available = True @@ -170,7 +170,7 @@ def summarize(self, post_title: str, post_body: str) -> PostSummary: f"{self._base_url}/v1/chat/completions", { "messages": [{"role": "user", "content": prompt}], - "mode": "route", + "mode": "auto", "reasoning_effort": self._reasoning_effort, }, headers={"authorization": f"Bearer {self._api_key}"}, diff --git a/scripts/apply_adaptive_orchestrator_default.py b/scripts/apply_adaptive_orchestrator_default.py deleted file mode 100644 index 77e83cccd..000000000 --- a/scripts/apply_adaptive_orchestrator_default.py +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env python3 -"""Migrate active contextual-orchestrator consumers from route to auto.""" -from __future__ import annotations - -import os -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -EXPECTED_BRANCH = "agent/adaptive-orchestrator-default" -ACTIVE_CLIENTS = ( - "lineageweave/post_summary.py", - "lineageweave/post_evaluation.py", - "lineageweave/keyman_extraction.py", - "lineageweave/commitment_extraction.py", - "lineageweave/post_chat.py", - "lineageweave/entity_relationship_classification.py", -) - - -def replace_once(text: str, old: str, new: str, label: str) -> str: - """Replace exactly one expected repository fragment.""" - count = text.count(old) - if count != 1: - raise RuntimeError(f"{label}: expected one match, found {count}") - return text.replace(old, new, 1) - - -def main() -> None: - """Patch code and add policy evidence.""" - branch = os.environ.get("GITHUB_REF_NAME", EXPECTED_BRANCH) - if branch != EXPECTED_BRANCH: - raise RuntimeError(f"refusing to mutate unexpected branch: {branch}") - - for relative in ACTIVE_CLIENTS: - path = ROOT / relative - text = path.read_text(encoding="utf-8") - original = text - text = text.replace('"mode": "route"', '"mode": "auto"') - text = text.replace('mode="route"', 'mode="auto"') - text = text.replace('mode: str = "route"', 'mode: str = "auto"') - if text == original: - raise RuntimeError(f"{relative}: expected a route default to migrate") - path.write_text(text, encoding="utf-8") - - keyman_path = ROOT / "lineageweave" / "keyman_extraction.py" - keyman = keyman_path.read_text(encoding="utf-8") - keyman = replace_once( - keyman, - '''that benefits from the orchestrator's reasoning-effort allocation, not a -single confidence number, so it uses ``mode="auto"`` (one worker call) at -a ``"medium"`` reasoning effort by default rather than ``verify``'s -worker-plus-checker pattern, which is reserved for adjudication's binary -judgment calls. -''', - '''that benefits from the orchestrator's task-sensitive allocation of model, -reasoning effort, and workflow depth. It therefore uses ``mode="auto"`` at -a ``"medium"`` reasoning effort by default; contextual-orchestrator may use -a single worker or escalate to verification/conducted work when the detected -quality requirement justifies the additional cost. -''', - "keyman policy explanation", - ) - keyman_path.write_text(keyman, encoding="utf-8") - - changelog_path = ROOT / "CHANGELOG.md" - changelog = changelog_path.read_text(encoding="utf-8") - changelog = replace_once( - changelog, - "## [0.71.0] - 2026-08-14\n", - "## [Unreleased]\n\n### Changed\n\n" - "- Active contextual-orchestrator clients now request `mode=\"auto\"` rather than forcing a one-model route. The orchestrator owns the minimum-cost route, verification, or conducted workflow that satisfies the detected quality requirement; explicit modes remain available for controlled experiments and operator overrides.\n\n" - "## [0.71.0] - 2026-08-14\n", - "changelog", - ) - changelog_path.write_text(changelog, encoding="utf-8") - - test_path = ROOT / "tests" / "test_contextual_orchestrator_default_policy.py" - if test_path.exists(): - raise RuntimeError(f"refusing to replace existing policy test: {test_path}") - test_path.write_text(POLICY_TEST, encoding="utf-8") - - adr_path = ROOT / "docs" / "adr" / "0005-adaptive-orchestrator-default.md" - if adr_path.exists(): - raise RuntimeError(f"refusing to replace existing ADR: {adr_path}") - adr_path.write_text(ADR, encoding="utf-8") - - -POLICY_TEST = '''"""Contract tests for adaptive contextual-orchestrator consumer defaults.""" -from __future__ import annotations - -from pathlib import Path -import unittest - -ROOT = Path(__file__).resolve().parents[1] -ACTIVE_CLIENTS = ( - "lineageweave/post_summary.py", - "lineageweave/post_evaluation.py", - "lineageweave/keyman_extraction.py", - "lineageweave/commitment_extraction.py", - "lineageweave/post_chat.py", - "lineageweave/entity_relationship_classification.py", -) - - -class AdaptiveOrchestratorDefaultTest(unittest.TestCase): - """Protect production clients from regressing to forced one-model routing.""" - - def test_active_clients_use_auto_and_never_force_route(self) -> None: - for relative in ACTIVE_CLIENTS: - source = (ROOT / relative).read_text(encoding="utf-8") - with self.subTest(path=relative): - self.assertNotIn('"mode": "route"', source) - self.assertNotIn('mode="route"', source) - self.assertNotIn('mode: str = "route"', source) - self.assertTrue( - '"mode": "auto"' in source - or 'mode="auto"' in source - or 'mode: str = "auto"' in source - ) - - def test_high_stakes_adjudication_retains_explicit_checked_override(self) -> None: - source = (ROOT / "lineageweave/adjudication_client.py").read_text(encoding="utf-8") - self.assertIn('"mode": "verify"', source) - - -if __name__ == "__main__": - unittest.main() -''' - -ADR = '''# ADR-0005: Adaptive contextual-orchestrator mode is the consumer default - -- Status: Accepted -- Date: 2026-08-15 - -## Context - -LineageWeave previously forced `mode="route"` in summarization, post evaluation, -Keyman extraction, commitment extraction, post chat, and relationship -classification. That made the consumer choose a single model before -contextual-orchestrator could evaluate task difficulty, capability fit, -verification need, and known model price. - -Research on adaptive orchestration and cost-aware reliability shows that no fixed -model/workflow/budget choice dominates for all requests. Dynamic scaffolding and -query-level cost allocation are therefore responsibilities of the orchestration -plane, not of each domain client. - -## Decision - -Active general-purpose clients request `mode="auto"`. - -- contextual-orchestrator selects the quality-sufficient route, bounded - verification, or conducted workflow and then minimizes known cost inside the - selected capability tier; -- LineageWeave continues to own prompts, schemas, strict parsing, domain evidence, - and failure semantics; -- the low-volume lineage adjudication channel retains the explicit `verify` - override because an independently checked verdict is part of that domain - contract, not an accidental routing default; -- explicit modes remain permitted for ablation, regression comparison, and - emergency operator policy, but they are not ordinary production defaults. - -## Consequences - -Trace width is no longer a stable consumer assumption for `auto` requests. -Telemetry and tests must record the requested policy and actual trace. Cost -claims require configured price evidence; an unpriced model is never treated as -free. - -## References - -Omidvar, H., & Akhlaghi, V. (2026). *A communication-theoretic framework for LLM agents: Cost-aware adaptive reliability* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2605.09121 - -Tang, Y., Cetin, E., Xu, J., Sun, Q., Nielsen, S., Richard, V., Goda, H., Tymchenko, I., Nguyen, N., Lee, H., Ashiga, M., Kotyan, S., Kuroki, S., & Clanuwat, T. (2026). *Sakana Fugu technical report* [Technical report]. arXiv. https://doi.org/10.48550/arXiv.2606.21228 -''' - -if __name__ == "__main__": - main() diff --git a/tests/test_contextual_orchestrator_default_policy.py b/tests/test_contextual_orchestrator_default_policy.py new file mode 100644 index 000000000..6c5eb5d7c --- /dev/null +++ b/tests/test_contextual_orchestrator_default_policy.py @@ -0,0 +1,40 @@ +"""Contract tests for adaptive contextual-orchestrator consumer defaults.""" +from __future__ import annotations + +from pathlib import Path +import unittest + +ROOT = Path(__file__).resolve().parents[1] +ACTIVE_CLIENTS = ( + "lineageweave/post_summary.py", + "lineageweave/post_evaluation.py", + "lineageweave/keyman_extraction.py", + "lineageweave/commitment_extraction.py", + "lineageweave/post_chat.py", + "lineageweave/entity_relationship_classification.py", +) + + +class AdaptiveOrchestratorDefaultTest(unittest.TestCase): + """Protect production clients from regressing to forced one-model routing.""" + + def test_active_clients_use_auto_and_never_force_route(self) -> None: + for relative in ACTIVE_CLIENTS: + source = (ROOT / relative).read_text(encoding="utf-8") + with self.subTest(path=relative): + self.assertNotIn('"mode": "route"', source) + self.assertNotIn('mode="route"', source) + self.assertNotIn('mode: str = "route"', source) + self.assertTrue( + '"mode": "auto"' in source + or 'mode="auto"' in source + or 'mode: str = "auto"' in source + ) + + def test_high_stakes_adjudication_retains_explicit_checked_override(self) -> None: + source = (ROOT / "lineageweave/adjudication_client.py").read_text(encoding="utf-8") + self.assertIn('"mode": "verify"', source) + + +if __name__ == "__main__": + unittest.main() From 28fa477937bc9aae851ffe85ecca8f1b4d0457ca Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 20:42:21 +0900 Subject: [PATCH 4/7] test: stage adaptive orchestration default regressions --- ...tage_adaptive_orchestrator_default_test.py | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 scripts/stage_adaptive_orchestrator_default_test.py diff --git a/scripts/stage_adaptive_orchestrator_default_test.py b/scripts/stage_adaptive_orchestrator_default_test.py new file mode 100644 index 000000000..c81b94dcd --- /dev/null +++ b/scripts/stage_adaptive_orchestrator_default_test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +"""Stage regressions for LineageWeave's adaptive orchestration default.""" + +from __future__ import annotations + +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +TEST_PATH = ROOT / "tests" / "test_adaptive_orchestrator_default.py" +CONTENT = '''"""LineageWeave delegates product-default LLM execution to auto policy.""" + +from __future__ import annotations + +from pathlib import Path + +from lineageweave import post_evaluation + + +class _Response: + """OpenAI-compatible response body used by the transport seam.""" + + choices = [{"message": {"content": "{}"}}] + + +def test_post_evaluation_adapter_defaults_to_auto(monkeypatch) -> None: + observed: dict[str, object] = {} + + def fake_post_json(url, payload, *, headers, timeout): + observed.update( + url=url, + payload=payload, + headers=headers, + timeout=timeout, + ) + return {"choices": [{"message": {"content": "{}"}}]} + + monkeypatch.setattr(post_evaluation, "post_json", fake_post_json) + adapter = post_evaluation._OrchestratorCompleteAdapter( + "https://orchestrator.example.test", "inference_token" + ) + adapter.complete([{"role": "user", "content": "Evaluate this evidence."}]) + + assert observed["payload"]["mode"] == "auto" + + +def test_post_evaluation_judge_uses_auto_by_default() -> None: + client = post_evaluation.ContextualOrchestratorPostEvaluationClient( + "https://orchestrator.example.test", "inference_token" + ) + assert client._judge.mode == "auto" + + +def test_runtime_clients_do_not_force_single_model_route() -> None: + package_root = Path(__file__).resolve().parents[1] / "lineageweave" + violations: list[str] = [] + for path in sorted(package_root.glob("*.py")): + text = path.read_text(encoding="utf-8") + if '"mode": "route"' in text or "'mode': 'route'" in text: + violations.append(f"{path.name}: request payload") + if 'mode="route"' in text or "mode='route'" in text: + violations.append(f"{path.name}: constructor/call default") + if 'mode: str = "route"' in text or "mode: str = 'route'" in text: + violations.append(f"{path.name}: typed default") + assert violations == [] +''' + +if TEST_PATH.exists(): + if TEST_PATH.read_text(encoding="utf-8") != CONTENT: + raise SystemExit(f"refusing to replace a different existing test: {TEST_PATH}") +else: + TEST_PATH.write_text(CONTENT, encoding="utf-8") From 397308c94a3a090cc221688a350607b8108a3a5c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 20:42:53 +0900 Subject: [PATCH 5/7] feat: stage adaptive orchestration defaults --- .../apply_adaptive_orchestrator_default.py | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 scripts/apply_adaptive_orchestrator_default.py diff --git a/scripts/apply_adaptive_orchestrator_default.py b/scripts/apply_adaptive_orchestrator_default.py new file mode 100644 index 000000000..2a4d53fbf --- /dev/null +++ b/scripts/apply_adaptive_orchestrator_default.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""Replace product-default single-route calls with contextual-orchestrator auto.""" + +from __future__ import annotations + +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +PACKAGE_ROOT = ROOT / "lineageweave" +ADR_PATH = ROOT / "docs" / "adr" / "0005-adaptive-contextual-orchestrator-default.md" +CHANGELOG_PATH = ROOT / "CHANGELOG.md" + +replacements = { + '"mode": "route"': '"mode": "auto"', + "'mode': 'route'": "'mode': 'auto'", + 'mode="route"': 'mode="auto"', + "mode='route'": "mode='auto'", + 'mode: str = "route"': 'mode: str = "auto"', + "mode: str = 'route'": "mode: str = 'auto'", + 'with ``mode="route"``': 'with ``mode="auto"``', + 'uses ``mode="route"``': 'uses ``mode="auto"``', +} + +changed_files: list[Path] = [] +for path in sorted(PACKAGE_ROOT.glob("*.py")): + text = path.read_text(encoding="utf-8") + updated = text + for old, new in replacements.items(): + updated = updated.replace(old, new) + if updated != text: + path.write_text(updated, encoding="utf-8") + changed_files.append(path) + +if not changed_files: + # Idempotent continuation is allowed only when the desired source state is + # already present. The permanent regression independently proves it. + remaining = [] + for path in sorted(PACKAGE_ROOT.glob("*.py")): + text = path.read_text(encoding="utf-8") + for legacy in replacements: + if legacy in text: + remaining.append(f"{path}:{legacy}") + if remaining: + raise RuntimeError("legacy route defaults remain: " + ", ".join(remaining)) + +ADR_PATH.parent.mkdir(parents=True, exist_ok=True) +if not ADR_PATH.exists(): + ADR_PATH.write_text( + '''# ADR-0005: Product LLM clients delegate default execution to contextual-orchestrator auto + +- Status: Accepted +- Date: 2026-08-16 + +## Context + +LineageWeave had several independent feature adapters for summarization, Keyman +extraction, relationship classification, commitments, chat, and post evaluation. +Each adapter hard-coded `route`, which duplicated policy and forced a single worker +regardless of uncertainty, risk, or task complexity. Adjudication separately uses +`verify` because it is an explicit controlled worker-plus-checker contract. + +## Decision + +Every production adapter that does not intentionally implement a controlled +ablation sends `mode="auto"`. Contextual-orchestrator owns model/provider selection, +reasoning effort, verification depth, failover, and the quality-first/cost-aware +execution tier. The explicit adjudication `verify` contract remains unchanged. + +The application still owns prompt semantics, strict parsers, typed domain records, +tenant authorization, persistence, and fail-closed handling. Auto orchestration is +not permission to accept malformed or unsupported model output. + +## Consequences + +A simple extraction may still resolve to one worker when that is the +quality-sufficient least-cost plan. Evaluation and uncertain classification can use +a verifier, while complex synthesis can use a conducted workflow, without changing +LineageWeave's public interfaces. Returned trace and usage evidence remain available +for empirical calibration. + +## References + +Omidvar, H., & Akhlaghi, V. (2026). *A communication-theoretic framework for LLM agents: Cost-aware adaptive reliability* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2605.09121 + +Tang, Y., Cetin, E., Xu, J., Sun, Q., Nielsen, S., Richard, V., Goda, H., Tymchenko, I., Nguyen, N., Lee, H., Ashiga, M., Kotyan, S., Kuroki, S., & Clanuwat, T. (2026). *Sakana Fugu technical report* [Technical report]. arXiv. https://doi.org/10.48550/arXiv.2606.21228 +''', + encoding="utf-8", + ) + +changelog = CHANGELOG_PATH.read_text(encoding="utf-8") +entry = ( + "- Product LLM adapters now delegate their default execution tier to " + "contextual-orchestrator `auto` instead of forcing a single-model `route`; " + "the explicit adjudication `verify` contract remains unchanged.\n" +) +if entry not in changelog: + insertion = "## [Unreleased]\n\n### Changed\n\n" + entry + "\n" + marker = "## [0.71.0]" + if marker not in changelog: + raise RuntimeError("CHANGELOG latest release marker was not found") + changelog = changelog.replace(marker, insertion + marker, 1) + CHANGELOG_PATH.write_text(changelog, encoding="utf-8") From 3514b379c29058231029914625591b0f0501de49 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 20:43:12 +0900 Subject: [PATCH 6/7] ci: apply and verify adaptive orchestration defaults --- .../apply-adaptive-orchestrator-default.yml | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/apply-adaptive-orchestrator-default.yml diff --git a/.github/workflows/apply-adaptive-orchestrator-default.yml b/.github/workflows/apply-adaptive-orchestrator-default.yml new file mode 100644 index 000000000..7172ca8a8 --- /dev/null +++ b/.github/workflows/apply-adaptive-orchestrator-default.yml @@ -0,0 +1,94 @@ +name: Apply adaptive contextual-orchestrator defaults + +on: + push: + branches: + - agent/adaptive-orchestrator-default + paths: + - scripts/stage_adaptive_orchestrator_default_test.py + - scripts/apply_adaptive_orchestrator_default.py + - .github/workflows/apply-adaptive-orchestrator-default.yml + +permissions: + contents: write + +concurrency: + group: apply-adaptive-orchestrator-default-${{ github.ref }} + cancel-in-progress: false + +jobs: + red-green-verify: + runs-on: ubuntu-latest + timeout-minutes: 90 + steps: + - name: Checkout exact branch head + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: true + + - name: Set up Python + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Set up Rust for fast-mlsirm + uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 + + - name: Install product and test dependencies + shell: bash + run: | + set -euo pipefail + python -m pip install --upgrade pip + python -m pip install -e '.[dev,backend]' + + - name: Stage the default-mode regressions + run: python scripts/stage_adaptive_orchestrator_default_test.py + + - name: Establish red state or recognize an already-applied source change + id: red + shell: bash + run: | + set -euo pipefail + set +e + python -m pytest -q tests/test_adaptive_orchestrator_default.py > /tmp/adaptive-default-red.log 2>&1 + status=$? + set -e + cat /tmp/adaptive-default-red.log + if [ "$status" -eq 0 ]; then + echo "already_applied=true" >> "$GITHUB_OUTPUT" + else + grep -Eq "FAILED|ERROR" /tmp/adaptive-default-red.log + echo "already_applied=false" >> "$GITHUB_OUTPUT" + fi + + - name: Apply source, ADR, and changelog changes + run: python scripts/apply_adaptive_orchestrator_default.py + + - name: Prove the focused regression is green + run: python -m pytest -q tests/test_adaptive_orchestrator_default.py + + - name: Run the complete repository suite + run: python -m pytest -q + + - name: Verify syntax and patch integrity + shell: bash + run: | + python -m compileall -q lineageweave tests/test_adaptive_orchestrator_default.py + git diff --check + + - name: Publish the verified source commit + env: + TARGET_BRANCH: agent/adaptive-orchestrator-default + shell: bash + run: | + set -euo pipefail + rm scripts/stage_adaptive_orchestrator_default_test.py + rm scripts/apply_adaptive_orchestrator_default.py + rm .github/workflows/apply-adaptive-orchestrator-default.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add --all + git diff --cached --check + git commit -m "feat(ai): delegate product defaults to adaptive orchestration" + git push origin "HEAD:${TARGET_BRANCH}" From cb946597f56be1750ff9b4b151a8307d2519d653 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 12:40:57 +0000 Subject: [PATCH 7/7] feat(ai): delegate product defaults to adaptive orchestration --- .../apply-adaptive-orchestrator-default.yml | 94 ---------------- CHANGELOG.md | 6 ++ ...daptive-contextual-orchestrator-default.md | 37 +++++++ .../apply_adaptive_orchestrator_default.py | 102 ------------------ .../test_adaptive_orchestrator_default.py | 18 +--- 5 files changed, 44 insertions(+), 213 deletions(-) delete mode 100644 .github/workflows/apply-adaptive-orchestrator-default.yml create mode 100644 docs/adr/0005-adaptive-contextual-orchestrator-default.md delete mode 100644 scripts/apply_adaptive_orchestrator_default.py rename scripts/stage_adaptive_orchestrator_default_test.py => tests/test_adaptive_orchestrator_default.py (76%) diff --git a/.github/workflows/apply-adaptive-orchestrator-default.yml b/.github/workflows/apply-adaptive-orchestrator-default.yml deleted file mode 100644 index 7172ca8a8..000000000 --- a/.github/workflows/apply-adaptive-orchestrator-default.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Apply adaptive contextual-orchestrator defaults - -on: - push: - branches: - - agent/adaptive-orchestrator-default - paths: - - scripts/stage_adaptive_orchestrator_default_test.py - - scripts/apply_adaptive_orchestrator_default.py - - .github/workflows/apply-adaptive-orchestrator-default.yml - -permissions: - contents: write - -concurrency: - group: apply-adaptive-orchestrator-default-${{ github.ref }} - cancel-in-progress: false - -jobs: - red-green-verify: - runs-on: ubuntu-latest - timeout-minutes: 90 - steps: - - name: Checkout exact branch head - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # actions/checkout@v4 - with: - fetch-depth: 0 - persist-credentials: true - - - name: Set up Python - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # actions/setup-python@v6 - with: - python-version: "3.12" - - - name: Set up Rust for fast-mlsirm - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 - - - name: Install product and test dependencies - shell: bash - run: | - set -euo pipefail - python -m pip install --upgrade pip - python -m pip install -e '.[dev,backend]' - - - name: Stage the default-mode regressions - run: python scripts/stage_adaptive_orchestrator_default_test.py - - - name: Establish red state or recognize an already-applied source change - id: red - shell: bash - run: | - set -euo pipefail - set +e - python -m pytest -q tests/test_adaptive_orchestrator_default.py > /tmp/adaptive-default-red.log 2>&1 - status=$? - set -e - cat /tmp/adaptive-default-red.log - if [ "$status" -eq 0 ]; then - echo "already_applied=true" >> "$GITHUB_OUTPUT" - else - grep -Eq "FAILED|ERROR" /tmp/adaptive-default-red.log - echo "already_applied=false" >> "$GITHUB_OUTPUT" - fi - - - name: Apply source, ADR, and changelog changes - run: python scripts/apply_adaptive_orchestrator_default.py - - - name: Prove the focused regression is green - run: python -m pytest -q tests/test_adaptive_orchestrator_default.py - - - name: Run the complete repository suite - run: python -m pytest -q - - - name: Verify syntax and patch integrity - shell: bash - run: | - python -m compileall -q lineageweave tests/test_adaptive_orchestrator_default.py - git diff --check - - - name: Publish the verified source commit - env: - TARGET_BRANCH: agent/adaptive-orchestrator-default - shell: bash - run: | - set -euo pipefail - rm scripts/stage_adaptive_orchestrator_default_test.py - rm scripts/apply_adaptive_orchestrator_default.py - rm .github/workflows/apply-adaptive-orchestrator-default.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add --all - git diff --cached --check - git commit -m "feat(ai): delegate product defaults to adaptive orchestration" - git push origin "HEAD:${TARGET_BRANCH}" diff --git a/CHANGELOG.md b/CHANGELOG.md index f52171bda..324e3f5bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ All notable changes to this project are documented here. Format follows - Active contextual-orchestrator clients now request `mode="auto"` rather than forcing a one-model route. The orchestrator owns the minimum-cost route, verification, or conducted workflow that satisfies the detected quality requirement; explicit modes remain available for controlled experiments and operator overrides. +## [Unreleased] + +### Changed + +- Product LLM adapters now delegate their default execution tier to contextual-orchestrator `auto` instead of forcing a single-model `route`; the explicit adjudication `verify` contract remains unchanged. + ## [0.71.0] - 2026-08-14 ### Added diff --git a/docs/adr/0005-adaptive-contextual-orchestrator-default.md b/docs/adr/0005-adaptive-contextual-orchestrator-default.md new file mode 100644 index 000000000..790046e58 --- /dev/null +++ b/docs/adr/0005-adaptive-contextual-orchestrator-default.md @@ -0,0 +1,37 @@ +# ADR-0005: Product LLM clients delegate default execution to contextual-orchestrator auto + +- Status: Accepted +- Date: 2026-08-16 + +## Context + +LineageWeave had several independent feature adapters for summarization, Keyman +extraction, relationship classification, commitments, chat, and post evaluation. +Each adapter hard-coded `route`, which duplicated policy and forced a single worker +regardless of uncertainty, risk, or task complexity. Adjudication separately uses +`verify` because it is an explicit controlled worker-plus-checker contract. + +## Decision + +Every production adapter that does not intentionally implement a controlled +ablation sends `mode="auto"`. Contextual-orchestrator owns model/provider selection, +reasoning effort, verification depth, failover, and the quality-first/cost-aware +execution tier. The explicit adjudication `verify` contract remains unchanged. + +The application still owns prompt semantics, strict parsers, typed domain records, +tenant authorization, persistence, and fail-closed handling. Auto orchestration is +not permission to accept malformed or unsupported model output. + +## Consequences + +A simple extraction may still resolve to one worker when that is the +quality-sufficient least-cost plan. Evaluation and uncertain classification can use +a verifier, while complex synthesis can use a conducted workflow, without changing +LineageWeave's public interfaces. Returned trace and usage evidence remain available +for empirical calibration. + +## References + +Omidvar, H., & Akhlaghi, V. (2026). *A communication-theoretic framework for LLM agents: Cost-aware adaptive reliability* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2605.09121 + +Tang, Y., Cetin, E., Xu, J., Sun, Q., Nielsen, S., Richard, V., Goda, H., Tymchenko, I., Nguyen, N., Lee, H., Ashiga, M., Kotyan, S., Kuroki, S., & Clanuwat, T. (2026). *Sakana Fugu technical report* [Technical report]. arXiv. https://doi.org/10.48550/arXiv.2606.21228 diff --git a/scripts/apply_adaptive_orchestrator_default.py b/scripts/apply_adaptive_orchestrator_default.py deleted file mode 100644 index 2a4d53fbf..000000000 --- a/scripts/apply_adaptive_orchestrator_default.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -"""Replace product-default single-route calls with contextual-orchestrator auto.""" - -from __future__ import annotations - -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -PACKAGE_ROOT = ROOT / "lineageweave" -ADR_PATH = ROOT / "docs" / "adr" / "0005-adaptive-contextual-orchestrator-default.md" -CHANGELOG_PATH = ROOT / "CHANGELOG.md" - -replacements = { - '"mode": "route"': '"mode": "auto"', - "'mode': 'route'": "'mode': 'auto'", - 'mode="route"': 'mode="auto"', - "mode='route'": "mode='auto'", - 'mode: str = "route"': 'mode: str = "auto"', - "mode: str = 'route'": "mode: str = 'auto'", - 'with ``mode="route"``': 'with ``mode="auto"``', - 'uses ``mode="route"``': 'uses ``mode="auto"``', -} - -changed_files: list[Path] = [] -for path in sorted(PACKAGE_ROOT.glob("*.py")): - text = path.read_text(encoding="utf-8") - updated = text - for old, new in replacements.items(): - updated = updated.replace(old, new) - if updated != text: - path.write_text(updated, encoding="utf-8") - changed_files.append(path) - -if not changed_files: - # Idempotent continuation is allowed only when the desired source state is - # already present. The permanent regression independently proves it. - remaining = [] - for path in sorted(PACKAGE_ROOT.glob("*.py")): - text = path.read_text(encoding="utf-8") - for legacy in replacements: - if legacy in text: - remaining.append(f"{path}:{legacy}") - if remaining: - raise RuntimeError("legacy route defaults remain: " + ", ".join(remaining)) - -ADR_PATH.parent.mkdir(parents=True, exist_ok=True) -if not ADR_PATH.exists(): - ADR_PATH.write_text( - '''# ADR-0005: Product LLM clients delegate default execution to contextual-orchestrator auto - -- Status: Accepted -- Date: 2026-08-16 - -## Context - -LineageWeave had several independent feature adapters for summarization, Keyman -extraction, relationship classification, commitments, chat, and post evaluation. -Each adapter hard-coded `route`, which duplicated policy and forced a single worker -regardless of uncertainty, risk, or task complexity. Adjudication separately uses -`verify` because it is an explicit controlled worker-plus-checker contract. - -## Decision - -Every production adapter that does not intentionally implement a controlled -ablation sends `mode="auto"`. Contextual-orchestrator owns model/provider selection, -reasoning effort, verification depth, failover, and the quality-first/cost-aware -execution tier. The explicit adjudication `verify` contract remains unchanged. - -The application still owns prompt semantics, strict parsers, typed domain records, -tenant authorization, persistence, and fail-closed handling. Auto orchestration is -not permission to accept malformed or unsupported model output. - -## Consequences - -A simple extraction may still resolve to one worker when that is the -quality-sufficient least-cost plan. Evaluation and uncertain classification can use -a verifier, while complex synthesis can use a conducted workflow, without changing -LineageWeave's public interfaces. Returned trace and usage evidence remain available -for empirical calibration. - -## References - -Omidvar, H., & Akhlaghi, V. (2026). *A communication-theoretic framework for LLM agents: Cost-aware adaptive reliability* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2605.09121 - -Tang, Y., Cetin, E., Xu, J., Sun, Q., Nielsen, S., Richard, V., Goda, H., Tymchenko, I., Nguyen, N., Lee, H., Ashiga, M., Kotyan, S., Kuroki, S., & Clanuwat, T. (2026). *Sakana Fugu technical report* [Technical report]. arXiv. https://doi.org/10.48550/arXiv.2606.21228 -''', - encoding="utf-8", - ) - -changelog = CHANGELOG_PATH.read_text(encoding="utf-8") -entry = ( - "- Product LLM adapters now delegate their default execution tier to " - "contextual-orchestrator `auto` instead of forcing a single-model `route`; " - "the explicit adjudication `verify` contract remains unchanged.\n" -) -if entry not in changelog: - insertion = "## [Unreleased]\n\n### Changed\n\n" + entry + "\n" - marker = "## [0.71.0]" - if marker not in changelog: - raise RuntimeError("CHANGELOG latest release marker was not found") - changelog = changelog.replace(marker, insertion + marker, 1) - CHANGELOG_PATH.write_text(changelog, encoding="utf-8") diff --git a/scripts/stage_adaptive_orchestrator_default_test.py b/tests/test_adaptive_orchestrator_default.py similarity index 76% rename from scripts/stage_adaptive_orchestrator_default_test.py rename to tests/test_adaptive_orchestrator_default.py index c81b94dcd..98affc0c0 100644 --- a/scripts/stage_adaptive_orchestrator_default_test.py +++ b/tests/test_adaptive_orchestrator_default.py @@ -1,13 +1,4 @@ -#!/usr/bin/env python3 -"""Stage regressions for LineageWeave's adaptive orchestration default.""" - -from __future__ import annotations - -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -TEST_PATH = ROOT / "tests" / "test_adaptive_orchestrator_default.py" -CONTENT = '''"""LineageWeave delegates product-default LLM execution to auto policy.""" +"""LineageWeave delegates product-default LLM execution to auto policy.""" from __future__ import annotations @@ -62,10 +53,3 @@ def test_runtime_clients_do_not_force_single_model_route() -> None: if 'mode: str = "route"' in text or "mode: str = 'route'" in text: violations.append(f"{path.name}: typed default") assert violations == [] -''' - -if TEST_PATH.exists(): - if TEST_PATH.read_text(encoding="utf-8") != CONTENT: - raise SystemExit(f"refusing to replace a different existing test: {TEST_PATH}") -else: - TEST_PATH.write_text(CONTENT, encoding="utf-8")