diff --git a/TODO.md b/TODO.md index 33305bd1..6fcecdb0 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,10 @@ ## Active tickets +- [ ] [`ticket-089`](project/ticket-089/README.md) — route semantic requests + through public SubLLM with direct Z.AI GLM 5.3 by default. Current state: + `IN_PROGRESS / PUBLICATION`; workstream: `llm`. + - [ ] [`ticket-090`](project/ticket-090/README.md) — make the default offline test command independent of ambient SubLLM credentials. Current state: `IN_PROGRESS / PUBLICATION`; workstream: `integration`. diff --git a/project/TICKETS.md b/project/TICKETS.md index 27c66ed5..21709dfe 100644 --- a/project/TICKETS.md +++ b/project/TICKETS.md @@ -63,6 +63,7 @@ of `project/README.md`, which remains a generated technical-analysis artifact. | **ticket-085** | [`README.md`](./ticket-085/README.md) | [`preprompt.md`](./ticket-085/preprompt.md) | - | [`ai-codex.md`](./ticket-085/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-085/ai-codex-logs.txt) | [`changelog.md`](./ticket-085/changelog.md) | | **ticket-087** | [`README.md`](./ticket-087/README.md) | [`preprompt.md`](./ticket-087/preprompt.md) | - | [`ai-codex.md`](./ticket-087/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-087/ai-codex-logs.txt) | [`changelog.md`](./ticket-087/changelog.md) | | **ticket-088** | [`README.md`](./ticket-088/README.md) | [`preprompt.md`](./ticket-088/preprompt.md) | - | [`ai-codex.md`](./ticket-088/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-088/ai-codex-logs.txt) | [`changelog.md`](./ticket-088/changelog.md) | +| **ticket-089** | [`README.md`](./ticket-089/README.md) | [`preprompt.md`](./ticket-089/preprompt.md) | - | [`ai-codex.md`](./ticket-089/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-089/ai-codex-logs.txt) | [`changelog.md`](./ticket-089/changelog.md) | | **ticket-090** | [`README.md`](./ticket-090/README.md) | [`preprompt.md`](./ticket-090/preprompt.md) | - | [`ai-codex.md`](./ticket-090/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-090/ai-codex-logs.txt) | [`changelog.md`](./ticket-090/changelog.md) | | **ticket-091** | [`README.md`](./ticket-091/README.md) | [`preprompt.md`](./ticket-091/preprompt.md) | - | [`ai-codex.md`](./ticket-091/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-091/ai-codex-logs.txt) | [`changelog.md`](./ticket-091/changelog.md) | diff --git a/project/ticket-089/README.md b/project/ticket-089/README.md new file mode 100644 index 00000000..33f6bf97 --- /dev/null +++ b/project/ticket-089/README.md @@ -0,0 +1,27 @@ +# Ticket 089: Use public SubLLM direct Z.AI GLM 5.3 + +- **ID**: ticket-089 +- **Owner**: agent:codex under SESSION_EXECUTION_AUTHORIZATION +- **Status**: IN_PROGRESS +- **Workflow state**: PUBLICATION +- **Created**: 2026-08-26 + +## Goal and scope + +Make the public `subactor/subllm` policy the default route for every semantic +LLM request. The central policy selects direct Z.AI GLM 5.3. Keep the legacy +OpenRouter path only behind an explicit `T2C_USE_SUBLLM=false` compatibility +override; never silently bypass a requested or default SubLLM route. + +## Acceptance criteria + +- [x] AC-01: Scope is explicitly approved by the Founder in the originating request. +- [x] AC-02: SubLLM is enabled when no routing environment variable is set. +- [x] AC-03: The resolved direct Z.AI route uses `glm-5.3` and the public Todo2code repository URL. +- [x] AC-04: `T2C_USE_SUBLLM=false` remains the only explicit compatibility opt-out. +- [x] AC-05: The repository verification suite passes before publication. + +## Participants + +- Human participant: Founder approval captured in the originating request; no user-* file was created. +- Agent participant: [ai-codex.md](ai-codex.md) diff --git a/project/ticket-089/ai-codex-logs.txt b/project/ticket-089/ai-codex-logs.txt new file mode 100644 index 00000000..e69de29b diff --git a/project/ticket-089/ai-codex.md b/project/ticket-089/ai-codex.md new file mode 100644 index 00000000..32e46d93 --- /dev/null +++ b/project/ticket-089/ai-codex.md @@ -0,0 +1,31 @@ +--- +participant-id: agent:codex +participant: codex +role: agent +ticket: ticket-089 +--- +# Participant: codex (AI agent) + +## Understanding + +The existing bridge already resolves and executes public SubLLM routes, but it +only activates automatically when local SubLLM-specific environment variables +or a sibling source checkout are present. Ordinary installations therefore +silently continue through the legacy OpenRouter transport. + +## Execution plan + +1. Make SubLLM the default routing policy while preserving explicit opt-out. +2. Update the direct Z.AI fixture to GLM 5.3 and the canonical repository URL. +3. Run the repository verification suite and publish through the governed PR flow. + +## Actual changes + +- Changed semantic LLM routing to SubLLM-by-default. +- Preserved `T2C_USE_SUBLLM=false` for explicit compatibility and isolated legacy unit fixtures. +- Updated the central-route contract fixture from GLM 5.2 to direct Z.AI GLM 5.3. +- Verified TypeScript, module boundaries, environment/workflow contracts, generated schemas and 430 tests (429 passed, 1 skipped, 0 failed). + +## Blockers + +- None. diff --git a/project/ticket-089/changelog.md b/project/ticket-089/changelog.md new file mode 100644 index 00000000..4ee67852 --- /dev/null +++ b/project/ticket-089/changelog.md @@ -0,0 +1,11 @@ +# Ticket Changelog (ticket-089) + +## [0.1.0] - 2026-08-26 + +- Initial governance scaffold created. +- No human participant identity or content was generated. +# Changelog + +- Default semantic LLM requests to the public `subactor/subllm` policy. +- Expect the direct Z.AI `glm-5.3` route and canonical `autogrammar/todo2code` provenance. +- Retain legacy OpenRouter behavior only through explicit `T2C_USE_SUBLLM=false`. diff --git a/project/ticket-089/intent.json b/project/ticket-089/intent.json new file mode 100644 index 00000000..cf91754c --- /dev/null +++ b/project/ticket-089/intent.json @@ -0,0 +1,75 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-089", + "summary": "Use public SubLLM direct Z.AI GLM 5.3", + "workstream": "llm", + "classification": { + "kind": "SERVICE", + "priority": "P2", + "origin": "health" + }, + "allowedPaths": [ + "src/llm/subllm.ts", + "test/subllm.test.ts", + "project/ticket-089/**", + "TODO.md", + "project/TICKETS.md" + ], + "forbiddenPaths": ["project/ticket-*/user-*.md"], + "stacks": ["typescript", "node", "subllm", "zai"], + "dependsOn": [], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "5e89819bfaf986f08d7e6d9d136a9929437d37e5", + "targetBranch": "main", + "outcome": "Route semantic requests through public SubLLM with direct Z.AI GLM 5.3 by default", + "nonGoals": [ + "Remove the explicit legacy compatibility path", + "Change non-LLM extraction" + ], + "complexity": "S", + "estimatedMinutes": 15, + "budgets": { + "maxImplementationFiles": 4, + "maxAffectedComponents": 1, + "maxPublicInterfaceChanges": 0, + "maxRuntimeDependencies": 0 + }, + "architecture": { + "status": "accepted", + "decision": "Use SubLLM as the semantic policy boundary and retain OpenRouter only behind explicit opt-out", + "components": [ + { + "name": "semantic-llm-bridge", + "paths": [ + "src/llm/subllm.ts", + "test/*llm*", + "test/helpers.ts" + ] + } + ], + "responsibilityChanges": false, + "interfaceChanges": [], + "dataChanges": [], + "ui": { + "impact": "none", + "states": [], + "evidence": [] + }, + "rollback": "Set T2C_USE_SUBLLM=false or revert the routing commit" + }, + "runtimeDependencies": [], + "validation": [ + { + "criterion": "AC-05", + "commands": [ + "make verify", + "./project/governance-check.sh", + "git diff --check" + ], + "evidence": "project/ticket-089/ai-codex-logs.txt" + } + ] + } +} diff --git a/project/ticket-089/preprompt.md b/project/ticket-089/preprompt.md new file mode 100644 index 00000000..621c40f1 --- /dev/null +++ b/project/ticket-089/preprompt.md @@ -0,0 +1,8 @@ +# Ticket preprompt + +- **Task ID**: ticket-089 +- **Task title**: Use public SubLLM direct Z.AI GLM 5.3 +- **Created**: 2026-08-26T06:07:17Z + +Keep executable implementation outside this governance/evidence directory. +Read a human-owned user-*.md file only when one exists. diff --git a/src/llm/subllm.ts b/src/llm/subllm.ts index 25ccdc0b..017b688f 100644 --- a/src/llm/subllm.ts +++ b/src/llm/subllm.ts @@ -38,7 +38,7 @@ export function lastResolvedSubllmRoute(): SubllmPublicRoute | null { export function shouldUseSubllm( environment: NodeJS.ProcessEnv = process.env, - cwd = process.cwd(), + _cwd = process.cwd(), ): boolean { const explicit = environment.T2C_USE_SUBLLM?.trim().toLowerCase(); if (explicit && FALSE_VALUES.has(explicit)) return false; @@ -49,7 +49,7 @@ export function shouldUseSubllm( if (environment.SUBLLM_ENV_FILE || environment.SUBLLM_POLICY_FILE || environment.SUBLLM_PYTHONPATH) { return true; } - return Boolean(localSubllmPythonPath(cwd)); + return true; } export async function resolveSubllmRoute( diff --git a/test/subllm.test.ts b/test/subllm.test.ts index e2efd4a7..77a52d4a 100644 --- a/test/subllm.test.ts +++ b/test/subllm.test.ts @@ -34,15 +34,15 @@ if args[:3] == ["resolve", "todo2code", "semantic"]: print(json.dumps({ "application": "todo2code", "application_name": "todo2code", - "application_url": "https://github.com/semcod/todo2code", + "application_url": "https://github.com/autogrammar/todo2code", "function": "semantic", "provider": "zai", - "model": "glm-5.2", - "priority": 10, + "model": "glm-5.3", + "priority": 0, "api_base": "https://api.z.ai/api/coding/paas/v4", "api_key_env": "ZAI_API_KEY", - "litellm_model": "zai/glm-5.2", - "wire_model": "glm-5.2", + "litellm_model": "zai/glm-5.3", + "wire_model": "glm-5.3", "extra_headers": {}, })) elif args == ["env", "path"]: @@ -92,7 +92,7 @@ test('SubLLM bridge resolves the selected central route without command-shell in assert.equal(shouldUseSubllm(), true); const resolved = await resolveSubllmRoute(); assert.equal(resolved.route.provider, 'zai'); - assert.equal(resolved.route.wire_model, 'glm-5.2'); + assert.equal(resolved.route.wire_model, 'glm-5.3'); assert.equal(resolved.route.application, 'todo2code'); assert.equal(resolved.credential, FIXTURE_CREDENTIAL); assert.equal(JSON.stringify(resolved.route).includes('fixture-value'), false); @@ -116,7 +116,7 @@ test('todo2code sends structured semantic requests through direct Z.AI resolved return new Response(JSON.stringify({ id: 'zai-fixture-response', request_id: body.request_id, - model: 'glm-5.2', + model: 'glm-5.3', usage: { prompt_tokens: 12, completion_tokens: 4, total_tokens: 16 }, choices: [{ message: { content: responseContent } }], }), { status: 200, headers: { 'Content-Type': 'application/json' } }); @@ -131,13 +131,13 @@ test('todo2code sends structured semantic requests through direct Z.AI resolved ); assert.deepEqual(result.value, { ok: true }); - assert.equal(result.metadata.model, 'glm-5.2'); + assert.equal(result.metadata.model, 'glm-5.3'); assert.equal(result.metadata.provider, 'zai'); assert.equal(url, 'https://api.z.ai/api/coding/paas/v4/chat/completions'); assert.equal(headers.Authorization, `Bearer ${FIXTURE_CREDENTIAL}`); assert.equal(headers['X-OpenRouter-Title'], undefined); assert.equal(headers['HTTP-Referer'], undefined); - assert.equal(body.model, 'glm-5.2'); + assert.equal(body.model, 'glm-5.3'); assert.equal(body.user_id, 'todo2code'); assert.match(String(body.request_id), /^todo2code-semantic-[0-9a-f]{32}$/u); assert.deepEqual(body.response_format, { type: 'json_object' }); @@ -154,9 +154,9 @@ test('todo2code sends structured semantic requests through direct Z.AI resolved application: 'todo2code', function: 'semantic', provider: 'zai', - model: 'glm-5.2', - wireModel: 'glm-5.2', - priority: 10, + model: 'glm-5.3', + wireModel: 'glm-5.3', + priority: 0, apiBase: 'https://api.z.ai/api/coding/paas/v4', }); assert.equal(JSON.stringify(audit).includes('fixture-value'), false); @@ -174,6 +174,12 @@ test('todo2code sends structured semantic requests through direct Z.AI resolved } }); +test('SubLLM is the default semantic route and legacy OpenRouter requires an explicit opt-out', () => { + assert.equal(shouldUseSubllm({}), true); + assert.equal(shouldUseSubllm({ T2C_USE_SUBLLM: 'true' }), true); + assert.equal(shouldUseSubllm({ T2C_USE_SUBLLM: 'false' }), false); +}); + test('explicitly requested SubLLM fails closed when its package is unavailable', async () => { const previousUse = process.env.T2C_USE_SUBLLM; const previousPath = process.env.SUBLLM_PYTHONPATH;