diff --git a/project/TICKETS.md b/project/TICKETS.md index d69446fb..ae48b21e 100644 --- a/project/TICKETS.md +++ b/project/TICKETS.md @@ -439,4 +439,6 @@ project analysis or human-owned ticket inputs. | **ticket-439** | [`README.md`](./ticket-439/README.md) | - | - | - | - | - | | **ticket-440** | [`README.md`](./ticket-440/README.md) | - | - | - | - | - | | **ticket-441** | [`README.md`](./ticket-441/README.md) | - | - | - | - | - | +| **ticket-442** | [`README.md`](./ticket-442/README.md) | - | - | - | - | - | +| **ticket-443** | [`README.md`](./ticket-443/README.md) | - | - | - | - | - | diff --git a/project/ticket-445/README.md b/project/ticket-445/README.md new file mode 100644 index 00000000..112d19a0 --- /dev/null +++ b/project/ticket-445/README.md @@ -0,0 +1,23 @@ +# Ticket 445: Report actual SubLLM model in queue execution evidence + +- **ID**: ticket-445 +- **Owner**: agent:codex +- **Status**: IN_PROGRESS +- **Workflow state**: PUBLICATION +- **Created**: 2026-10-08 + +## Goal and scope + +SESSION_EXECUTION_AUTHORIZATION: the user requested autonomous service and bug fixing, verification of Willman/Koru/SubLLM/OpenCode and protected delivery. Intake: paxlet-com/willman PLF-113, bounded follow-up PLF-115. A real local GPT-OSS response was labeled cursor/grok-4.6 by the queue summary. Correct the label from the runner result without changing execution or admission. + +## Acceptance criteria + +- [x] AC-01: The executed result model wins over the requested/default model; legacy runners retain fallback labels and exit codes. +- [x] AC-02: Targeted regression and managed governance checks pass. +- [ ] AC-03: Exact-head OneDev and independent Validator approve protected publication. + +## Evidence + +External receipt set: receipt:minis-autonomy-20261008/koru-provenance. Source scope: src/koru/queue/runner.py and tests/test_queue_model_provenance.py. No fleet writer is enabled by this change. + +Targeted regression: 45 passed. Managed governance: PASS, 0 warnings. Source/test lint: PASS. Protected exact-head CI and independent merge approval remain required. diff --git a/project/ticket-445/intent.json b/project/ticket-445/intent.json new file mode 100644 index 00000000..249f1934 --- /dev/null +++ b/project/ticket-445/intent.json @@ -0,0 +1,91 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-445", + "summary": "Report actual SubLLM model in queue execution evidence", + "workstream": "application", + "classification": { + "kind": "BUG", + "priority": "P2", + "origin": "requested" + }, + "allowedPaths": [ + "project/ticket-445/**", + "TODO.md", + "project/TICKETS.md", + "src/koru/queue/runner.py", + "tests/test_queue_model_provenance.py" + ], + "forbiddenPaths": [ + "project/ticket-*/user-*.md" + ], + "stacks": [ + "python", + "docker" + ], + "dependsOn": [], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "552ed81026c9213d05029c9ce395d2e01fa0ca7a", + "targetBranch": "main", + "outcome": "Queue completion and run-log labels report the actual SubLLM result model, including a local model chosen instead of the requested/default cloud model.", + "nonGoals": [ + "No provider route or permission changes", + "No automatic fleet execution or issue closure" + ], + "complexity": "S", + "estimatedMinutes": 20, + "budgets": { + "maxImplementationFiles": 2, + "maxAffectedComponents": 1, + "maxPublicInterfaceChanges": 0, + "maxRuntimeDependencies": 0 + }, + "architecture": { + "status": "accepted", + "decision": "Prefer optional result.model from the executed runner when building the queue action label; retain requested/default label for legacy CommandResult implementations without model metadata.", + "components": [ + { + "name": "queue-execution-evidence", + "paths": [ + "src/koru/queue/runner.py", + "tests/test_queue_model_provenance.py" + ] + } + ], + "responsibilityChanges": false, + "interfaceChanges": [], + "dataChanges": [], + "ui": { + "impact": "none", + "states": [], + "evidence": [] + }, + "rollback": "Revert the source/test delta; no stored state migration." + }, + "runtimeDependencies": [], + "validation": [ + { + "criterion": "AC-01", + "commands": [ + "python -m pytest -q tests/test_queue_model_provenance.py tests/test_queue_runners.py tests/test_queue_evidence.py" + ], + "evidence": "Executed model wins; requested/default fallback and failure propagation retain behavior." + }, + { + "criterion": "AC-02", + "commands": [ + "./project/governance-check.sh" + ], + "evidence": "Bounded source ownership and delivery contract validated." + }, + { + "criterion": "AC-03", + "commands": [ + "protected OneDev exact-head checks and independent Validator" + ], + "evidence": "Reviewed exact-head PR merged by protected controller." + } + ] + } +} diff --git a/src/koru/queue/runner.py b/src/koru/queue/runner.py index d7c7514c..cd9f8a52 100644 --- a/src/koru/queue/runner.py +++ b/src/koru/queue/runner.py @@ -299,7 +299,8 @@ def _execute_action( elif executor_kind == "llm": action = _enrich_llm_request_with_context(action, project) result = llm_runner(action, project) - action_label = f"llm {action.get('model') or _DEFAULT_LLM_MODEL}" + runtime_model = getattr(result, "model", None) + action_label = f"llm {runtime_model or action.get('model') or _DEFAULT_LLM_MODEL}" elif executor_kind in ("taskand", "process"): result = taskand_runner(action, project) action_label = f"taskand {action.get('uri') or 'orchestrator'}" diff --git a/tests/test_queue_model_provenance.py b/tests/test_queue_model_provenance.py new file mode 100644 index 00000000..4f906c46 --- /dev/null +++ b/tests/test_queue_model_provenance.py @@ -0,0 +1,47 @@ +from types import SimpleNamespace + +import pytest + +from koru.queue.runner import _execute_action +from koru.queue.runners import _DEFAULT_LLM_MODEL + + +@pytest.mark.parametrize( + ("runtime_model", "requested_model", "expected_model"), + [ + ("local-development/gpt-oss:20b", "cursor/grok-4.6", "local-development/gpt-oss:20b"), + ("local-development/gemma4:12b", None, "local-development/gemma4:12b"), + ("", "requested/model", "requested/model"), + (None, "requested/model", "requested/model"), + (None, None, _DEFAULT_LLM_MODEL), + ], +) +@pytest.mark.parametrize("exit_code", [0, 7]) +def test_queue_label_uses_executed_model( + monkeypatch, tmp_path, runtime_model, requested_model, expected_model, exit_code +): + monkeypatch.setattr("koru.queue.runner._enrich_llm_request_with_context", lambda action, _: action) + result = SimpleNamespace(returncode=exit_code, stdout="answer", stderr="diagnostic") + if runtime_model is not None: + result.model = runtime_model + request = {"prompt": "fixture"} + if requested_model is not None: + request["model"] = requested_model + + def run_llm(action, project): + assert action == request + assert project == tmp_path + return result + + def unexpected_runner(*args): + pytest.fail("another executor was selected") + + actual, label = _execute_action( + "llm", request, tmp_path, "PLF-001", unexpected_runner, run_llm, unexpected_runner + ) + + assert actual is result + assert actual.returncode == exit_code + assert actual.stdout == "answer" + assert actual.stderr == "diagnostic" + assert label == f"llm {expected_model}"