Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
43b6a50
feat(git): extract umbrella repository history
tom-sapletta-com Aug 1, 2026
df69bc8
chore(ticket-022): mark ticket as done and archive in TODO
tom-sapletta-com Aug 1, 2026
54b7727
chore(ticket-020): archive as done and update TODO
tom-sapletta-com Aug 1, 2026
806b33e
chore(todo): dedupe active-ticket list after closing ticket-020
tom-sapletta-com Aug 1, 2026
2950ed9
fix(docs): add markdown output
tom-sapletta-com Aug 4, 2026
e1f9f53
refactor: split diff ui html and related hotspots
tom-sapletta-com Aug 4, 2026
440546e
refactor: split executeAction handlers
tom-sapletta-com Aug 4, 2026
fdf44bd
refactor: split semantic rerank result assertion
tom-sapletta-com Aug 4, 2026
bf82943
refactor: split source patch assertions into focused helpers
tom-sapletta-com Aug 4, 2026
054e124
refactor: split plannable path checks into focused helpers
tom-sapletta-com Aug 4, 2026
1fd4141
refactor: route actions through typed handler map
tom-sapletta-com Aug 4, 2026
f118807
refactor: split proposeCodeChangePlans into focused helpers
tom-sapletta-com Aug 4, 2026
fc5f055
refactor: split source patch set validation helpers
tom-sapletta-com Aug 4, 2026
bd72a63
refactor: split code-change source patch builders
tom-sapletta-com Aug 4, 2026
3487b0f
refactor: split source patch edit and plan binding validation
tom-sapletta-com Aug 4, 2026
a7b4e1d
refactor: split implementation-helpers plan acceptance and apply paths
tom-sapletta-com Aug 4, 2026
9f9da72
chore: split implementation-helpers code-change orchestration
tom-sapletta-com Aug 4, 2026
fc28040
fix: restore todo patch contracts and reranker schema guard
tom-sapletta-com Aug 4, 2026
eb12c47
chore: remove unrelated project artifact diffs from refactor fix
tom-sapletta-com Aug 4, 2026
f71cd67
fix: close optionNumber call in cli graph diff
tom-sapletta-com Aug 4, 2026
b1dd60e
refactor: split source patch apply logic into dedicated module
tom-sapletta-com Aug 4, 2026
0c22f5c
fix(code-change): resolve source patch apply typing mismatches
tom-sapletta-com Aug 4, 2026
fff64da
fix(types): resolve refactor build blockers from analysis toon
tom-sapletta-com Aug 4, 2026
29ce649
fix(types): complete toon refactor intent and nl helper typing
tom-sapletta-com Aug 4, 2026
caf6551
fix(types): validate intent schema nodes before typed assertions
tom-sapletta-com Aug 4, 2026
995c7d4
refactor: split pipeline runner into focused modules
tom-sapletta-com Aug 4, 2026
35ec373
refactor: split reality view builder into separate module
tom-sapletta-com Aug 4, 2026
cf84fc0
refactor: move summary generation metadata builder to module
tom-sapletta-com Aug 4, 2026
8b20273
refactor: move operation plan generation assertion to own module
tom-sapletta-com Aug 4, 2026
2d2704b
refactor(toon): continue cli and live benchmark decomposition
tom-sapletta-com Aug 4, 2026
ea89865
Merge branch 'chore/refactor-toon-ui'
tom-sapletta-com Aug 4, 2026
a0b4a44
refactor(scripts): decompose live and env contract checks
tom-sapletta-com Aug 4, 2026
ffd963c
refactor(scripts): extract live model comparison output helpers
tom-sapletta-com Aug 4, 2026
b6da90c
refactor(scripts): centralize env contract problem reporting
tom-sapletta-com Aug 4, 2026
63e724d
refactor(scripts): isolate failed live manifest resolution
tom-sapletta-com Aug 4, 2026
a5dd9ab
refactor(scripts): validate live comparison models for forbidden Gemi…
tom-sapletta-com Aug 4, 2026
e41b690
refactor(scripts): centralize live contract artifact output
tom-sapletta-com Aug 4, 2026
04849e8
refactor(scripts): centralize env contract report evaluation
tom-sapletta-com Aug 4, 2026
eaaff9c
refactor(scripts): pass live contract history path explicitly
tom-sapletta-com Aug 4, 2026
26a90bd
refactor: split high-complexity extraction examples and checks
tom-sapletta-com Aug 4, 2026
7e39947
refactor: split python SDK basic example flow
tom-sapletta-com Aug 4, 2026
6b54972
refactor: split and wire-based intake CLI decoding
tom-sapletta-com Aug 4, 2026
e0ca353
refactor: split generation metadata synthesis helpers
tom-sapletta-com Aug 4, 2026
e9295eb
fix: repair syntax errors in generation validation and run helpers
tom-sapletta-com Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,29 @@
from MIT to Apache License 2.0; README and container/package metadata now use
the same SPDX identity.

## [0.5.2] - 2026-08-04

### Docs
- Update README.md
- Update TODO.md
- Update project/README.md
- Update project/context.md
- Update project/ticket-018/README.md
- Update project/ticket-018/changelog.md

### Other
- Update project/analysis.toon.yaml
- Update project/calls.mmd
- Update project/calls.png
- Update project/calls.toon.yaml
- Update project/calls.yaml
- Update project/compact_flow.mmd
- Update project/compact_flow.png
- Update project/evolution.toon.yaml
- Update project/flow.mmd
- Update project/flow.png
- ... and 38 more files

## [0.5.1] - 2026-08-01

### Docs
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@

## AI Cost Tracking

![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.5.1-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-36.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.5.2-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.69-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-50.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)

- 🤖 **LLM usage:** $3.8584 (110 commits)
- 👤 **Human dev:** ~$3603 (36.0h @ $100/h, 30min dedup)
- 🤖 **LLM usage:** $7.6898 (128 commits)
- 👤 **Human dev:** ~$4997 (50.0h @ $100/h, 30min dedup)

Generated on 2026-08-01 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
Generated on 2026-08-04 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)

---



![License](https://img.shields.io/badge/license-Apache--2.0-green)

`todo2code` buduje wspólny **Intent Evidence DSL** z poleceń, historii Git, aktualnego kodu, list zadań, changelogu i dokumentacji. Następnie łączy rekordy w graf przepływu wiedzy, wykrywa rozbieżności i generuje raport dla zespołu.
Expand Down
25 changes: 14 additions & 11 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@

## Active tickets

- [ ] [`ticket-020`](project/ticket-020/README.md) — implement a role-bound
trusted intake boundary with persistent manager/user/dev assignments,
CQRS/event sourcing, strict schemas, Protobuf, Python/TypeScript CLI, MCP and
A2A parity. Current state: `BLOCKED / VALIDATION`; implementation, full Node
verification and Docker core E2E pass. Policy 0.8.0 accepts tickets 018 and
020 in parallel; the global gate now reports only ticket-019's declared
dependency, conflict, ownership and overlap violations.

- [ ] [`ticket-019`](project/ticket-019/README.md) — publish the dependency-free
Python SDK as the root PyPI distribution `todo2code` through `goal -a`, with
one root `pyproject.toml` and SDK-only artifacts. Current state:
Expand All @@ -21,15 +13,26 @@
validator, trusted approval boundary, reusable governance CI, stack-specific
gates and pinned adoption in `todo2code`; extend it with safe concurrent
workstreams, dependency-aware intents and non-overlapping write scopes.
Current state: `IN_PROGRESS / EDIT` for the approved AC-18..AC-25: add a
Current state: `IN_PROGRESS / WAIT_FOR_APPROVAL` for the approved AC-11..AC-25:
pinned, read-only and attested `koru / code-review` PR check plus a required
ruleset. The workflow and live fail-closed semantic probe are verified;
ruleset `20186914` is staged for activation after the bootstrap evidence merge.
ruleset. `koru / code-review` and `governance / enforce` now run as required
checks on `main`; the ruleset is active with no bypass actors.
Earlier AC-11..AC-16 pass; AC-17 and the pre-existing publication/external
governance blockers remain recorded separately.

## Completed tickets

- [x] [`ticket-020`](project/ticket-020/README.md) — add deterministic
trusted intake boundary with CQRS/event sourcing, strict schemas, Protobuf,
Python/TypeScript CLI, MCP and A2A parity. Current state: `DONE`;
implementation and verification passes, and the implementation is complete.

- [x] [`ticket-022`](project/ticket-022/README.md) — add bounded, read-only Git
evidence extraction for umbrella workspaces such as Subactor. Current state:
`DONE`; 337 tests and Docker smoke pass. The Subactor run now extracts 326
commits from 39 member repositories, adds 41,792 net relations and reduces
same-snapshot diagnostics by 275.

- [x] [`ticket-017`](project/ticket-017/README.md) — repaired mutating command
help, Polish prohibition polarity and repository-bound path resolution;
independently audited the concurrent path/action-planning baseline and added
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.1
0.5.2
2 changes: 1 addition & 1 deletion adapters/tensorflow/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@todo2code/tensorflow-adapter-runtime",
"version": "0.5.1",
"version": "0.5.2",
"private": true,
"description": "Isolated optional TensorFlow runtime for todo2code action classification.",
"license": "Apache-2.0",
Expand Down
88 changes: 88 additions & 0 deletions examples/backend/src/request-handlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { type IncomingMessage, type ServerResponse } from 'node:http';
import { EventStore } from './store.js';
import { validateEventPayload } from './validation.js';

const MAX_BODY_BYTES = 64 * 1024;

export async function handleRequest(
request: IncomingMessage,
response: ServerResponse,
store: EventStore,
): Promise<void> {
const url = new URL(request.url ?? '/', `http://${request.headers.host ?? 'localhost'}`);
if (url.pathname === '/health' && request.method === 'GET') {
return handleHealth(response, store);
}
if (url.pathname === '/events' && request.method === 'POST') {
return handleEventPublish(request, response, store);
}
if (url.pathname === '/events' && request.method === 'GET') {
return handleEventList(response, url.searchParams, store);
}
sendJson(response, 404, { error: 'not found' });
}

async function handleHealth(response: ServerResponse, store: EventStore): Promise<void> {
sendJson(response, 200, { status: 'ok', events: store.size() });
}

async function handleEventPublish(request: IncomingMessage, response: ServerResponse, store: EventStore): Promise<void> {
const body = await readBody(request);
let payload: unknown;
try {
payload = JSON.parse(body || '{}');
} catch {
sendJson(response, 400, { error: 'invalid JSON body' });
return;
}

const validation = validateEventPayload(payload);
if (!validation.valid) {
process.stderr.write(`rejected event: ${validation.reason}\n`);
sendJson(response, 400, { error: validation.reason });
return;
}

const event = store.enqueueEvent(validation.agent, validation.action, validation.object);
sendJson(response, 202, { id: event.id });
}

async function handleEventList(response: ServerResponse, params: URLSearchParams, store: EventStore): Promise<void> {
const offset = parseOffset(params.get('offset'));
const limit = parseLimit(params.get('limit'));
sendJson(response, 200, store.listEvents(
offset,
limit,
));
}

function parseOffset(value: string | null): number {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : 0;
}

function parseLimit(value: string | null): number {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : 50;
}

async function readBody(request: IncomingMessage): Promise<string> {
const chunks: Buffer[] = [];
let size = 0;
for await (const chunk of request) {
const buffer = Buffer.from(chunk as Buffer);
size += buffer.byteLength;
if (size > MAX_BODY_BYTES) throw new Error('request body too large');
chunks.push(buffer);
}
return Buffer.concat(chunks).toString('utf8');
}

function sendJson(response: ServerResponse, status: number, payload: unknown): void {
const body = JSON.stringify(payload);
response.writeHead(status, {
'content-type': 'application/json; charset=utf-8',
'content-length': Buffer.byteLength(body),
});
response.end(body);
}
60 changes: 2 additions & 58 deletions examples/backend/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
// Mirrors the todo2code house style: node: builtins only, explicit body limits
// and no framework, so `t2c extract ast` sees plain TypeScript declarations.

import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';
import { createServer, type Server, type ServerResponse } from 'node:http';
import { EventStore } from './store.js';
import { validateEventPayload } from './validation.js';

const MAX_BODY_BYTES = 64 * 1024;
import { handleRequest } from './request-handlers.js';

export interface BackendOptions {
host?: string;
Expand All @@ -25,60 +23,6 @@ export function createBackend(options: BackendOptions = {}): { server: Server; s
return { server, store };
}

async function handleRequest(request: IncomingMessage, response: ServerResponse, store: EventStore): Promise<void> {
const url = new URL(request.url ?? '/', `http://${request.headers.host ?? 'localhost'}`);

if (request.method === 'GET' && url.pathname === '/health') {
sendJson(response, 200, { status: 'ok', events: store.size() });
return;
}

if (request.method === 'POST' && url.pathname === '/events') {
const body = await readBody(request);
let payload: unknown;
try {
payload = JSON.parse(body || '{}');
} catch {
sendJson(response, 400, { error: 'invalid JSON body' });
return;
}
const validation = validateEventPayload(payload);
if (!validation.valid) {
// Every rejection is logged with its reason, per the acceptance criteria.
process.stderr.write(`rejected event: ${validation.reason}\n`);
sendJson(response, 400, { error: validation.reason });
return;
}
const event = store.enqueueEvent(validation.agent, validation.action, validation.object);
sendJson(response, 202, { id: event.id });
return;
}

if (request.method === 'GET' && url.pathname === '/events') {
const offset = Number(url.searchParams.get('offset') ?? '0');
const limit = Number(url.searchParams.get('limit') ?? '50');
sendJson(response, 200, store.listEvents(
Number.isFinite(offset) ? offset : 0,
Number.isFinite(limit) ? limit : 50,
));
return;
}

sendJson(response, 404, { error: 'not found' });
}

async function readBody(request: IncomingMessage): Promise<string> {
const chunks: Buffer[] = [];
let size = 0;
for await (const chunk of request) {
const buffer = Buffer.from(chunk as Buffer);
size += buffer.byteLength;
if (size > MAX_BODY_BYTES) throw new Error('request body too large');
chunks.push(buffer);
}
return Buffer.concat(chunks).toString('utf8');
}

function sendJson(response: ServerResponse, status: number, payload: unknown): void {
const body = JSON.stringify(payload);
response.writeHead(status, {
Expand Down
12 changes: 10 additions & 2 deletions golang/ast_extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,18 @@ func parseFile(relative string, source []byte) ([]Fact, string) {

lines := strings.Split(string(source), "\n")
collector := &factCollector{relative: relative, fileSet: fileSet, lines: lines}
collectPackageFact(parsed, collector)
collectImportFacts(parsed, collector)
collectDeclarationFacts(parsed, collector)
return collector.facts, ""
}

func collectPackageFact(parsed *ast.File, collector *factCollector) {
collector.add(parsed.Name, "go_package_fact", "declare", parsed.Name.Name,
strPtr(parsed.Name.Name), nil, map[string]any{"package": parsed.Name.Name})
}

func collectImportFacts(parsed *ast.File, collector *factCollector) {
for _, importSpec := range parsed.Imports {
importPath, err := strconv.Unquote(importSpec.Path.Value)
if err != nil {
Expand All @@ -166,12 +174,12 @@ func parseFile(relative string, source []byte) ([]Fact, string) {
}
collector.add(importSpec, "go_import_fact", "depend_on", importPath, nil, nil, metadata)
}
}

func collectDeclarationFacts(parsed *ast.File, collector *factCollector) {
for _, declaration := range parsed.Decls {
collector.visitDecl(declaration, parsed.Name.Name)
}

return collector.facts, ""
}

type factCollector struct {
Expand Down
47 changes: 36 additions & 11 deletions java/JavaAstExtract.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,47 @@ private static void parseFile(
List<Map<String, Object>> facts,
List<String> warnings) throws Exception {
String source = Files.readString(file, StandardCharsets.UTF_8);
String relative = slash(root.relativize(file).toString());
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
try (StandardJavaFileManager manager = compiler.getStandardFileManager(diagnostics, Locale.ROOT, StandardCharsets.UTF_8)) {
Iterable<? extends JavaFileObject> units = manager.getJavaFileObjects(file.toFile());
JavacTask task = (JavacTask) compiler.getTask(null, manager, diagnostics,
List.of("-proc:none"), null, units);
Iterable<? extends CompilationUnitTree> parsed = task.parse();
Trees trees = Trees.instance(task);
SourcePositions positions = trees.getSourcePositions();
String relative = slash(root.relativize(file).toString());
for (CompilationUnitTree unit : parsed) {
new Collector(relative, source, unit, positions, facts).scan(unit, null);
}
ParsedJavaCompilation parsed = parseCompilationUnits(compiler, diagnostics, manager, file);
scanCompilationUnits(parsed, relative, source, facts);
}
collectFileDiagnostics(relative, diagnostics, warnings);
}

private static ParsedJavaCompilation parseCompilationUnits(
JavaCompiler compiler,
DiagnosticCollector<JavaFileObject> diagnostics,
StandardJavaFileManager manager,
Path file) throws IOException {
Iterable<? extends JavaFileObject> units = manager.getJavaFileObjects(file.toFile());
JavacTask task = (JavacTask) compiler.getTask(null, manager, diagnostics,
List.of("-proc:none"), null, units);
Iterable<? extends CompilationUnitTree> parsed = task.parse();
SourcePositions positions = Trees.instance(task).getSourcePositions();
return new ParsedJavaCompilation(parsed, positions);
}

private static void scanCompilationUnits(
ParsedJavaCompilation parsed,
String relative,
String source,
List<Map<String, Object>> facts) {
for (CompilationUnitTree unit : parsed.units()) {
new Collector(relative, source, unit, parsed.positions(), facts).scan(unit, null);
}
}

private record ParsedJavaCompilation(
Iterable<? extends CompilationUnitTree> units,
SourcePositions positions) {
}

private static void collectFileDiagnostics(String relative, DiagnosticCollector<JavaFileObject> diagnostics, List<String> warnings) {
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
warnings.add(slash(root.relativize(file).toString()) + ":" + diagnostic.getLineNumber()
warnings.add(relative + ":" + diagnostic.getLineNumber()
+ ": parse error: " + diagnostic.getMessage(Locale.ROOT));
}
}
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "todo2code",
"version": "0.5.1",
"version": "0.5.2",
"description": "todo2code (t2c): audited intent and team-communication extraction, evidence graphs, origin-to-workspace comparison and grounded summaries through CLI, MCP and A2A.",
"type": "module",
"private": true,
Expand Down
Loading
Loading