flowchart LR
NL[NL / ticket] --> NLO[Audited NL orchestrator]
NLO --> NLLM[OpenRouter structured extractor]
NLO --> NLE[Deterministic fallback]
GIT[Last N commits] --> GE[Git extractor]
CODE[TS JS Python Go Java Rust tree] --> AE[AST extractors]
TODO[TODO.md] --> TE[TODO converter]
CHG[CHANGELOG.md] --> CE[CHANGELOG converter]
TE --> ME[Markdown composition]
CE --> ME
ME --> MLO[Audited Markdown LLM enrichment]
DOCS[README ADR MODULE docs] --> ORE[OpenRouter document extractor]
COMM[project/ticket human + agent messages] --> COMME[Communication converter]
NLLM --> DSL[Canonical t2c Intent DSL]
NLE --> DSL
GE --> DSL
AE --> DSL
MLO --> DSL
ORE --> DSL
COMME --> DSL
DSL --> LINK[Deterministic linker]
LINK --> GRAPH[Intent evidence graph]
GRAPH --> DIAG[Deterministic diagnostics]
GRAPH --> SUM[OpenRouter summarizer]
DIAG --> SUM
SUM --> REPORT[Grounded team report]
CLI --> NLO
MCP --> CLI
A2A --> CLI
src/extractors/nl-llm.ts i src/extractors/nl.tsOrkiestrator LLM ma trzy jawne tryby: deterministic, prefer-llm i
require-llm. Structured output jest normalizowany przez runtime, nie może
podnieść lifecycle ponad proposed i zapisuje model oraz provenance. W
prefer-llm błąd dostaje stabilny kod (LLM_TIMEOUT, LLM_INVALID_MODEL, …),
a deterministyczny parser przejmuje operację z degraded=true. Sam nl.ts
segmentuje tekst i rozpoznaje modalność, negację, akcję, obiekt oraz targets;
może użyć lokalnego TensorFlow, lecz nie importuje OpenRouter.
src/extractors/git.tsCzyta ostatnie N commitów, autorów, timestampy, message/body, statusy plików, numstat i diff. Każdy commit ma oddzielny rekord; commit dokumentacyjny nie znika, tylko dostaje docOnly=true.
TypeScript Compiler API dostarcza fakty o importach, eksportach, symbolach i
wywołaniach. Python używa standardowego ast, Go go/ast, Java oficjalnego
JDK Compiler Tree API, a Rust parsera syn w izolowanym helperze Cargo. Każdy
adapter zwraca tę samą kopertę JSON {facts, warnings}, więc rdzeń nie zależy
od modelu AST konkretnego języka. Adapter nie uruchamia toolchainu, gdy nie ma
pasujących plików; brak dostępnego toolchainu daje ostrzeżenie, nie błąd całego
runu. AST jest faktem o stanie implementacji, a nie intencją człowieka.
src/extractors/todo.ts, src/extractors/changelog.ts i src/extractors/markdown.tsKażdy format ma własny konwerter i testowalny publiczny entrypoint. Checkbox
określa lifecycle planu, a wersja i kategoria changelogu określają claim
wydania. markdown.ts wyłącznie składa wyniki, nie miesza semantyki źródeł.
src/extractors/markdown-llm.tsDeterministyczne rekordy TODO/CHANGELOG są wysyłane w jednym ograniczonym
żądaniu structured output. Model zwraca dokładnie jedno wzbogacenie na istniejący
identyfikator i może zmienić tylko action, actor, object, polarity, targets oraz
acceptance evidence. Runtime zachowuje strukturę Markdown, lifecycle, wersję,
datę, kategorię, source lines i klasę epistemiczną. Brak klucza, timeout, błędny
model albo niepełna odpowiedź uruchamia jawny fallback lub błąd w require-llm.
src/extractors/docs-llm.tsDokumentacja jest dzielona według nagłówków i konfigurowalnego limitu znaków. Fragmenty są oceniane względem celów już znalezionych w NL/Git/AST/Markdown, a następnie ograniczane przez maksymalną liczbę chunków. Osobny timeout, współbieżność i limit rekordów wyznaczają górną granicę pracy. OpenRouter zwraca strukturalny JSON; runtime nadpisuje źródło, ogranicza zakres linii i confidence, dlatego model nie może podmienić provenance.
Każdy standalone wynik NL/Markdown/dokumentacji zawiera audit.runtimeVersion
i bezpieczne audit.configuration (model, URL, timeout, token budget,
temperatura i tryb structured output), bez klucza API. Dokumentacyjne rekordy
LLM mają ten sam metadata.generation co NL i Markdown.
src/extractors/communication.ts i src/communication/analyzer.tsPliki project/<ticket>/*.md|txt mają płaski front matter z uczestnikiem,
rolą human|agent, typem wiadomości i opcjonalnymi aliasami autora Git.
Konwerter emituje agent_log bez LLM. Analizator grupuje rekordy per uczestnik
i zestawia ich deklaracje/plany/claimy z komunikacją innych osób oraz dowodami
Git/AST. Brak tożsamości pozostaje jawnym problemem; raport agenta nie jest
podnoszony do klasy fact.
src/graph/linker.tsKandydaci są indeksowani po ticketach, symbolach, ścieżkach i tokenach obiektu.
Wspólny normalizator kanonizuje separatory ścieżek oraz symbole takie jak
crate::Runtime::validateContract(), Runtime.validateContract i
validateContract, zachowując aliasy do dopasowania między językami. Linker
przyznaje punkty za dowody i tworzy relacje deterministycznie. Nie wykonuje
zapytań sieciowych.
src/graph/diagnostics.tsPorównuje plany, claimy Git/CHANGELOG i fakty AST. Wynik nie zatwierdza pracy — identyfikuje ryzyka i wymagane decyzje.
src/summary/summarizer.tsDo OpenRouter trafia wyłącznie skompaktowany graf i diagnostyka. Surowy kod, diff i pełne dokumenty nie są wejściem summarizera.
src/comparison/workspace.tsRozwiązuje bazę (origin/main lub dowolny ref) do SHA i tworzy prywatny,
tymczasowy Git worktree. Ten sam runPipeline analizuje bazę oraz aktualny
filesystem, więc porównanie uwzględnia lokalne commity, staged, unstaged i
untracked bez modyfikowania katalogu użytkownika. Wynikiem jest diff grafów,
dwie projekcje reality oraz trend pokrycia. Narracyjne podsumowania przebiegów
bazowego i lokalnego są generowane deterministycznie; etap LLM summary jest
jawnie oznaczony jako skipped, aby porównanie nie wykonywało dwóch kosztownych
i semantycznie zbędnych zapytań. Worktree jest usuwany w finally.
src/core przechowuje wyłącznie modele, I/O, bezpieczeństwo i deterministyczne
prymitywy. Ekstraktory nie zależą od interfejsów; pipeline składa ekstraktory i
graf; services/actions.ts jest wspólną granicą CLI/MCP/A2A/SDK. Skrypt
verify-module-boundaries.mjs odrzuca cykle i importy z core do wyższych
warstw, a verify-no-llm-imports.mjs chroni deterministyczną część grafu.
core/schema.ts sprawdza pełny kontrakt t2c.intent/v1, t2c.graph/v1 i
t2c.diff/v1 na granicach linkera, diagnostyki, diffu i podsumowania.
src/interfaces/a2a.ts utrzymuje szybki store pamięciowy, a po ustawieniu
T2C_A2A_TASK_STORE otacza operacje transakcją plikową. Snapshot zawiera taski
wraz z właścicielem, historią i artefaktami; indeks idempotency jest odtwarzany
z wiadomości użytkownika. Blokada katalogowa koordynuje repliki, a zapis przez
plik tymczasowy i rename zapobiega częściowym snapshotom po awarii procesu.
Ścieżka jest sprawdzana względem T2C_ROOT również pod kątem symlinków.
src/watch/watcher.ts i src/core/ignore.tsWatcher cyklicznie buduje posortowany snapshot mtime:size, nie korzysta z
platformowo zależnego rekursywnego fs.watch. Katalogi wykluczone przez
.gitignore, .dockerignore i .intentignore są odcinane przed wejściem do
drzewa, a symlinki pomijane. Osobny interwał skanowania wykrywa zmiany, natomiast
minimalny interwał raportu agreguje je i ogranicza koszt pipeline’u oraz LLM.
Rekord nie jest „prawdą” bez kontekstu epistemicznego:
declaration — polecenie/ticket;plan — TODO;fact — AST;claim — Git i CHANGELOG;llm_inference — interpretacja NL lub dokumentacji przez OpenRouter.System zachowuje różnicę między planem, twierdzeniem autora i stanem kodu. Relacja nie zmienia klasy epistemicznej rekordów.
Identyfikatory i fingerprint grafu bazują na SHA-256 stabilnie serializowanych
danych. observedAt i timestamp runu mogą się zmieniać. Część deterministyczna
jest powtarzalna; porównanie z --docs-llm oraz NL w trybie LLM zależą od
odpowiedzi modelu, dlatego manifest zapisuje model, zwrócone metadane odpowiedzi,
parametry, fingerprint konfiguracji i status każdego etapu. Nieudany
require-llm zachowuje manifest awarii bez grafu. TensorFlow jest opcjonalny i
odizolowany od rdzenia, dlatego jego powtarzalność wymaga przypiętego adaptera,
modelu i słownika.