From ee7807ab4fdd67e5127003243c3a907b56f57976 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Wed, 26 Aug 2026 09:54:33 +0200 Subject: [PATCH 1/3] plan: govern Todo2code SubLLM default --- TODO.md | 4 ++ project/TICKETS.md | 1 + project/ticket-089/README.md | 27 ++++++++++ project/ticket-089/ai-codex-logs.txt | 0 project/ticket-089/ai-codex.md | 31 +++++++++++ project/ticket-089/changelog.md | 11 ++++ project/ticket-089/intent.json | 77 ++++++++++++++++++++++++++++ project/ticket-089/preprompt.md | 8 +++ 8 files changed, 159 insertions(+) create mode 100644 project/ticket-089/README.md create mode 100644 project/ticket-089/ai-codex-logs.txt create mode 100644 project/ticket-089/ai-codex.md create mode 100644 project/ticket-089/changelog.md create mode 100644 project/ticket-089/intent.json create mode 100644 project/ticket-089/preprompt.md 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..3744088f --- /dev/null +++ b/project/ticket-089/intent.json @@ -0,0 +1,77 @@ +{ + "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/helpers.ts", + "test/cli-summary.test.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. From b06ea800b98724466f74bd2ab1044bb3d0b96a0f Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Wed, 26 Aug 2026 09:54:33 +0200 Subject: [PATCH 2/3] feat(llm): default Todo2code to SubLLM Z.AI GLM 5.3 --- src/llm/subllm.ts | 4 ++-- test/cli-summary.test.ts | 7 ++++++- test/helpers.ts | 4 ++++ test/subllm.test.ts | 30 ++++++++++++++++++------------ 4 files changed, 30 insertions(+), 15 deletions(-) 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/cli-summary.test.ts b/test/cli-summary.test.ts index 3923f640..ee744b61 100644 --- a/test/cli-summary.test.ts +++ b/test/cli-summary.test.ts @@ -23,7 +23,12 @@ test('CLI summarize exposes deterministic, prefer-llm and require-llm modes', as const diagnostics = diagnoseGraph(graph, '2026-07-30T00:00:00.000Z'); await fs.writeFile(path.join(root, 'graph.json'), `${JSON.stringify(graph)}\n`, 'utf8'); await fs.writeFile(path.join(root, 'diagnostics.json'), `${JSON.stringify(diagnostics)}\n`, 'utf8'); - const environment = { ...process.env, OPENROUTER_API_KEY: '', T2C_ENV_FILE: 'missing.env' }; + const environment = { + ...process.env, + OPENROUTER_API_KEY: '', + T2C_ENV_FILE: 'missing.env', + T2C_USE_SUBLLM: 'false', + }; const base = ['summarize', 'graph.json', '--diagnostics', 'diagnostics.json']; const deterministic = await exec(process.execPath, [cli, ...base, '--mode', 'deterministic'], { diff --git a/test/helpers.ts b/test/helpers.ts index b7534bb5..628c1a92 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -1,5 +1,9 @@ import type { T2CConfig } from '../src/config/env.js'; +// Unit fixtures exercise the legacy transport unless a test explicitly opts +// into SubLLM. Production defaults to the centrally governed SubLLM route. +process.env.T2C_USE_SUBLLM ??= 'false'; + export function makeConfig(root: string): T2CConfig { return { root, 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; From ec7258fcfdd5b13bf9e9fe98bb782dbccacc97ba Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Wed, 26 Aug 2026 10:00:46 +0200 Subject: [PATCH 3/3] fix(governance): keep SubLLM change in llm workstream --- project/ticket-089/intent.json | 2 -- test/cli-summary.test.ts | 7 +------ test/helpers.ts | 4 ---- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/project/ticket-089/intent.json b/project/ticket-089/intent.json index 3744088f..cf91754c 100644 --- a/project/ticket-089/intent.json +++ b/project/ticket-089/intent.json @@ -10,8 +10,6 @@ }, "allowedPaths": [ "src/llm/subllm.ts", - "test/helpers.ts", - "test/cli-summary.test.ts", "test/subllm.test.ts", "project/ticket-089/**", "TODO.md", diff --git a/test/cli-summary.test.ts b/test/cli-summary.test.ts index ee744b61..3923f640 100644 --- a/test/cli-summary.test.ts +++ b/test/cli-summary.test.ts @@ -23,12 +23,7 @@ test('CLI summarize exposes deterministic, prefer-llm and require-llm modes', as const diagnostics = diagnoseGraph(graph, '2026-07-30T00:00:00.000Z'); await fs.writeFile(path.join(root, 'graph.json'), `${JSON.stringify(graph)}\n`, 'utf8'); await fs.writeFile(path.join(root, 'diagnostics.json'), `${JSON.stringify(diagnostics)}\n`, 'utf8'); - const environment = { - ...process.env, - OPENROUTER_API_KEY: '', - T2C_ENV_FILE: 'missing.env', - T2C_USE_SUBLLM: 'false', - }; + const environment = { ...process.env, OPENROUTER_API_KEY: '', T2C_ENV_FILE: 'missing.env' }; const base = ['summarize', 'graph.json', '--diagnostics', 'diagnostics.json']; const deterministic = await exec(process.execPath, [cli, ...base, '--mode', 'deterministic'], { diff --git a/test/helpers.ts b/test/helpers.ts index 628c1a92..b7534bb5 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -1,9 +1,5 @@ import type { T2CConfig } from '../src/config/env.js'; -// Unit fixtures exercise the legacy transport unless a test explicitly opts -// into SubLLM. Production defaults to the centrally governed SubLLM route. -process.env.T2C_USE_SUBLLM ??= 'false'; - export function makeConfig(root: string): T2CConfig { return { root,