todo-app/test/mcp/mcp_created_by_test.dart
Krzysztof kuhy Rudnicki 57019eec30
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file-length / file length <= 250 lines (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Track who filed a note (created_by)
New optional note field created_by (kuhy|claude), stored like by/repo and
omitted when unset so older builds stay wire-compatible. App UI stamps kuhy;
MCP add_task and the CLI stamp claude. list/get/search output includes it.
Human notes sort above Claude's; Claude notes are hidden behind a per-device
eye toggle. CLI --backfill-created-by [--dry-run] classifies old notes by the
node that wrote created_at, writing only the created_by field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:18:19 +01:00

89 lines
2.4 KiB
Dart

// add_task stamps created_by claude; every read tool reports it.
import 'package:flutter_test/flutter_test.dart';
import 'package:mcp_dart/mcp_dart.dart';
import 'package:todo/data/note.dart';
import 'mcp_harness.dart';
void main() {
late McpHarness h;
late McpClient c;
setUp(() async {
h = McpHarness();
await h.start();
c = await h.connect();
});
tearDown(() => h.dispose());
test('add_task is stamped claude and list/get/search show it', () async {
final added = await h.call(c, 'add_task', {
'repo': 'kuhyx/todo',
'title': 'Fix gate',
});
final id = idIn(added);
final stored = (await h.session.repository.listNotes()).single;
expect(stored.createdBy, 'claude');
expect(
await h.call(c, 'get_task', {'id': id}),
contains('created_by: claude'),
);
for (final listed in [
await h.call(c, 'list_tasks', {}),
await h.call(c, 'search_tasks', {'query': 'gate'}),
]) {
expect(listed.trim(), endsWith('\tclaude'));
}
});
test('a separate new_note task is stamped claude too', () async {
await h.call(c, 'add_task', {
'repo': 'kuhyx/todo',
'title': 'Own note',
'new_note': true,
});
expect((await h.session.repository.listNotes()).single.createdBy, 'claude');
});
test('a record without created_by reads as kuhy', () async {
final at = DateTime.utc(2026, 11);
await h.session.repository.upsert(
Note(
id: 'human-task-0001',
text: 'Human task',
priority: Priority.medium,
status: Status.todo,
createdAt: at,
updatedAt: at,
repo: 'kuhyx/todo',
),
);
expect(
await h.call(c, 'get_task', {'id': 'human-task-0001'}),
contains('created_by: kuhy'),
);
expect(
(await h.call(c, 'list_tasks', {})).trim(),
endsWith('Human task\tkuhy'),
);
});
test('joining a human-made repo note keeps its author', () async {
final at = DateTime.utc(2026, 11);
await h.session.repository.upsert(
Note(
id: 'human-task-0001',
text: 'todo todos',
priority: Priority.medium,
status: Status.todo,
createdAt: at,
updatedAt: at,
repo: 'kuhyx/todo',
createdBy: 'kuhy',
),
);
await h.call(c, 'add_task', {'repo': 'kuhyx/todo', 'title': 'More'});
expect((await h.session.repository.listNotes()).single.createdBy, 'kuhy');
});
}