matematic-patron-pr-review-pl
Recenzent PR/diffow PATRON - polskiego LegalTech AI agenta dla kancelarii. Cherry-pick struktury z dograh v1.31.0 review-pr (BSD-2, 286 linii), zaadaptowane pod kontekst MateMatic.
Komplementarny do:
- Wewnetrzny pipeline QA MateMatic dla tresci PL (artykuly, copy LI, BW) - ocena czytelnosci i poprawnosci. Ten skill ocenia diff kodu.
- matematic-konstytucja-ai (w tym hubie) - dokument governance dla klienta. Ten chroni kod produktu.
- Self-review pre-commit (6 zasad MateMatic) - poprzedza ten skill, sprawdza ogolne, ten skill nad nimi sprawdza repo-specific risks.
Kiedy uzywac
- Recenzja PR przed merge do
main w repo PATRON / KGLF / matematicsolutions MCP serwery
- Pre-commit audit wlasnego diffu w PATRONie
- Audyt zmian w komponentach krytycznych: mcp-security-gateway, audit_log, ring-policy, auth
- Po duzej refaktoryzacji - sweep pod katem regresji
- Przed pushem do
origin po sesji 3+ commitow
Glowne tryby awarii w repo PATRON
- Multi-tenant - brak org scoping na request-reachable read/write (kancelaria A widzi sprawe kancelarii B)
- Authless route lub websocket - silently public endpoint
- Webhook bez signature verification lub trust w unsigned fields
- SQL pisany poza
lib/db/*_client.ts - inkasacja warstwy
- Cache per-worker bez worker sync - stale state w innych procesach
- UI bypassuje generated SDK - direct
fetch('/api/v1/...') zamiast typed client
- Migracja niebezpieczna na produkcji - NOT NULL bez backfilla, brak downgrade()
- MCP tool reimplementuje auth zamiast
authenticate_mcp_request() (patrz matematic-mcp-fastmcp-instructions-pl w tym hubie)
- PII/cytat prawniczy w logach - naruszenie RODO + tajemnica adwokacka (art. 6 ust. 1 PrAdw + art. 3 ust. 3 RadcPrU)
- Brak audit_log entry dla operacji decyzyjnej (AI Act art. 12 record-keeping)
Jak prowadzic review
- Pobierz diff:
- GitHub PR:
gh pr diff <N> lub gh pr view <N> --json files,additions,deletions
- Local branch:
git diff origin/main...HEAD
- Pre-commit:
git diff HEAD
- Bucketuj zmienione pliki do sekcji nizej
- Czytaj aktualny kod jako source of truth przed finalizacja findings:
AGENTS.md (root + per-package) - org scoping i worker sync
- Dotknieci modele, db clients, routes, services, migrations
- Run TYLKO sekcje istotne dla zmienionych plikow
- Raportuj
<plik>:<linia> -> <problem> -> <correct pattern>
Freshness rule (KRYTYCZNE)
Traktuj ten plik jako review policy + navigation, NIE jako frozen inventory.
- Jesli aktualne repo PATRON klocy sie z tym skillem, ufaj repo i wymien drift jako problem.
- NIE polegaj na statycznych allowlistach ani konkretnych liniach z tego pliku.
- Recenzuj kod w PR i aktualnym repo, nie ten plik.
Mapa: sciezka w diffie -> sekcje do uruchomienia
| Ścieżka w diffie |
Sekcje |
app/routes/*.ts, apps/api/routes/ |
1, 2, 8 |
lib/db/*_client.ts, lib/db/schema.ts, lib/db/models.ts |
2, 3 |
lib/services/**/*.ts, apps/api/services/ |
2, 3, 4 |
lib/tasks/*.ts, apps/worker/ |
2, 3, 5 |
db/migrations/*.sql, lib/db/migrations/ |
6 |
mcp-servers/**, matematicsolutions/mcp-* |
1, 2, 7, kanon MCP (patrz matematic-mcp-fastmcp-instructions-pl) |
apps/ui/**, apps/dashboard/** |
9 |
lib/constants.ts, anything process.env outside lib/constants |
10 |
tests/**, __tests__/** |
11 |
lib/schemas/*.ts, lib/dto/*.ts |
12 |
lib/audit/**, lib/pii/**, lib/anonimizacja/** |
13 (MateMatic-specific) |
1. Route authentication
Brak globalnego middleware auth w PATRON. Kazda trasa deklaruje swoja auth.
Zaleznosci auth z lib/auth/depends.ts:
getUser (user kancelarii w organizacji)
getUserWs (websocket - kancelaria realtime)
getSuperuser (root MateMatic, NIE klient kancelaria)
requireRing(N) (ring-policy ADR-0027) - dla decyzji authorization
Checks:
- Nowy
@router.<verb>(...) bez auth dependency = silently public. Finding chyba ze plik ustanawia public auth pattern (np. webhook signed, public token).
getUser na impersonation / cross-org / global reporting -> powinno byc getSuperuser.
- Route reimplementujaca Bearer/X-API-Key parsing zamiast shared dependency = finding.
- WebSocket bez
Depends(getUserWs) i bez public-token flow = finding.
- Tightening CORS do fixed origin list potrzebuje strong justification - PATRON polega na cross-origin embedding (widget kancelarii).
- Nowy endpoint zwracajacy dane kancelarii BEZ wpiecia w ring-policy (
requireRing(2)+) = finding.
Komendy:
rg -n "Depends\((getUser|getUserWs|getSuperuser|requireRing)" app/routes/ apps/api/
rg -n "@router\.(get|post|put|delete|patch|websocket)" app/routes/
2. Organization scoping (THE CROSS-TENANT RULE - PRIORYTET #1)
NAJWAZNIEJSZA regula w PATRON. Kancelaria A NIGDY nie widzi danych kancelarii B. Kazdy request-reachable read/write resourca org-scoped MUSI filtrowac/walidowac przez organization_id.
Polega na: AGENTS.md canonical summary + ADR-0027 ring-policy.
Determinacja scope:
- Direct scope: model ma
organization_id (cases, documents, prompts, agents)
- Indirect scope: model siega org przez parent FK (e.g. comments -> document -> org)
- Legacy spelling moze istniec w starych migracjach (
org_id, tenant_id), ale nowy kod uzywa organization_id
Checks:
- Kazdy
*ById(...) / getXById(...) w route handler = suspicious. Jesli request-reachable i unscoped = finding.
- Nowe
list* / get* endpointy filtruja w SQL (WHERE organization_id = ?), NIE w TS po .all().
- Jesli request pisze FK do innego org-scoped resourca, route MUSI najpierw fetch target row z
user.selectedOrganizationId i odrzucic jesli nie nalezy do org.
- Services wolane z routes preserva scoping. Drop
organization_id w DB client call = trace caller.
- Background tasks NIE dostaja org context for free. Musza reload parent row i derive org z tego.
- Webhooki derive org z signed identifier, NIE z caller-supplied body fields
organization_id.
- Nowy kod uzywa kanoniczne
organizationId, nie orgId, tenantId, organisationId.
Komendy:
rg -n "ById\(" app/routes/ lib/services/ apps/worker/
rg -n "dbClient\.get\w+\(" app/routes/ lib/services/
rg -n "organizationId|selectedOrganizationId|requireRing" app/routes/ lib/services/ apps/worker/ lib/db/
3. DB query layering
Production SQL nalezy do lib/db/*_client.ts. Routes, services, tasks WOLAJA db client methods, NIE pisza Drizzle/SQL bezposrednio.
Checks:
db.select, db.update, db.delete, db.insert, sql\`, prepare(, transaction(wapp/routes/, lib/services/, apps/worker/` = finding.
lib/services/adminUtils/ to wyjatek - NIE jest template'em dla production.
- Session lifecycle w db client.
- Nowe params db client uzywaja kanoniczne
organizationId.
Komendy:
rg -n "(db\.select|db\.update|db\.delete|db\.insert|sql\`)" app/routes/ lib/services/ apps/worker/
4. Worker sync - multi-process state coherence
Production PATRON ma multi-worker. Per-process mutable caches stale unless broadcast.
Checks:
- Nowy module-level / class-level mutable cache pisany przez endpoint potrzebuje WorkerSyncManager broadcast path.
- Local invalidation alone NIE wystarcza jesli inni workerzy moga jeszcze serwowac stale state.
- Jesli PR wprowadza nowy cached object, diff powinien zawierac:
- broadcast call
- event type / signal definition
- handler registration ktory reload fresh state
5. Background tasks / queue workers
Checks:
- User-triggered enqueue paths waliduja org ownership przed enqueue.
- Tasks ktore akceptuja ID i reload row musza derive org z tego row, NIE assume shared context.
- Tasks idempotentne lub explicit retry-safe.
- Tylko real task entrypoints w
apps/worker/queue.ts::routes.
- Secret logging rules z sekcji 10 dotycza tu.
6. Migrations (db/migrations/*.sql lub Drizzle migrations)
Checks:
up i down istnieja i sa meaningfully reversible chyba ze zmiana naprawde nie da sie cofnac.
NOT NULL column do zaludnionej tabeli potrzebuje safe default lub backfilla przed constraint.
- Tightening nullable -> NOT NULL potrzebuje backfilla PRZED
ALTER COLUMN ... SET NOT NULL.
- Nowe JSON columny match JSON/JSONB convention tabeli.
- Big backfills w migracji - pytaj. Czesto naleza out-of-band.
- Indexy na duzych tabelach (kancelarii produkcyjnych) potrzebuja concurrent-safe handling (
CREATE INDEX CONCURRENTLY).
- NIE traktuj historical migration naming jako finding sam w sobie. Recenzuj zmieniana migracje, nie stara prose.
7. MCP servers (mcp-servers/**, matematicsolutions/mcp-*)
Reguly z matematic-mcp-fastmcp-instructions-pl - 8 elementow kanonu.
Checks:
- Nowe tools uzywaja
authenticateMcpRequest() (lub Pythonowy authenticate_mcp_request()), NIE reimplementuja API-key validation.
- Nowe tool DB lookups preserva org scoping jak REST routes.
- Tools wolajace external URLs waliduja URL i konsideruja SSRF.
- Nowe MCP tool wymieniony w
instructions ma istniec w registry (drift test).
errorCode zwracane przez tool sa w docstring tool (drift test).
- ToolAnnotations dla read-only (
readOnlyHint=true) dla tooli ktore nie mutuja.
8. Telephony / webhook handlers
Checks:
- Nowy provider webhook flow implementuje
verifyInboundSignature() lub provider equivalent.
- Minimal pre-verification work moze byc wymagana zeby zidentyfikowac candidate config, ALE route NIE robi unrelated workflow/user/stateful work przed verification.
- Org derivation z provider identifiers walidowanych przez webhook auth flow.
- Webhook NIE ufa raw body
organizationId.
- Jesli webhook referencuje numer telefonu, walidacja ze numer istnieje dla derived org.
9. UI (apps/ui/**, apps/dashboard/**) - generated SDK only
Frontend rozmawia z backendem przez apps/ui/src/client/ (generated typed SDK).
Checks:
fetch('/api/v1/...') lub fetch(\${backendUrl}/api/v1/...`)` w app code = finding chyba ze aktualny kod udowadnia narrow exception.
- Hardcoded backend URLs = finding.
- Manualna konstrukcja
Authorization header w zwyklych komponentach = finding (auth injected centrally).
- SDK calls firowane przed auth state ready = finding.
- Local interfaces duplikujace generated types = finding.
- Backend API shape zmienione + UI konsumuje =
apps/ui/src/client/ powinno tez sie zmienic.
10. Logging, secrets, constants
Checks:
- Nowy kod uzywa shared logger (np.
pino z PII masking), NIE console.log.
- Nowy
process.env.X poza lib/constants.ts = finding.
- NIE logujemy: API keys, bearer tokens, credentials, full webhook bodies, PII klienta kancelarii (PESEL, NIP, imiona, sygnatury aktualnych spraw).
- Common offender shapes:
logger.info(\config: ${JSON.stringify(config)}`)`
logger.debug(requestBody)
- Logging raw config / user configuration rows
11. Tests (tests/**, __tests__/**)
Checks:
- Async waits uzywaja bounded timeout (
pTimeout, setTimeout race), NIE while (!done).
- Tests run against
.env.test, NIE .env.
- Integration tests NIE neutered przez mockowanie zeby test passed - musza hit prawdziwy testowy DB.
- Tests zalezne od mutable shared DB state across test cases = suspicious.
12. Schemas (lib/schemas/*.ts, lib/dto/*.ts)
Checks:
- Nowe response schemas NIE expose internal FKs / IDs chyba ze caller naprawde potrzebuje.
- Request schemas akceptujace org-scoped FK values = trigger do inspekcji corresponding route pod katem section 2 ownership validation.
13. PATRON-specific - PII, audit_log, AI Act art. 12
Tej sekcji NIE ma w dograh - to MateMatic-specific dla legal AI.
Checks:
- Operacja decyzyjna (klasyfikacja dokumentu, rekomendacja, generowanie pisma, anonimizacja) MUSI zapisac do
audit_log (ADR-0033). Brak entry = finding (AI Act art. 12 record-keeping).
- PII detection / anonimizacja inline PRZED storage uzytkowych logow (matematic-anonimizacja-pl jako pre-storage filter). Bypass = finding.
- Cytat z orzeczenia / ustawy w odpowiedzi LLM musi przejsc citation-grounding-pl (mechaniczna weryfikacja string-match). Jesli kod generuje odpowiedz LLM bez tego layera = finding.
- Pisma procesowe MUSZA przejsc wewnetrzny pipeline QA MateMatic (anti-slop PL + senior review min 2 rundy) przed docx. Kod generujacy .docx bez tej walidacji = finding.
- Dane z prawdziwych akt klienta (kwoty, sygnatury, inicjaly) w README/aktualnosci/post LI = czerwona linia tajemnicy adwokackiej (art. 6 ust. 1 PrAdw) / radcowskiej (art. 3 ust. 3 RadcPrU). Grep przed push.
- Nowy retention policy: dane klienta kancelarii max 90 dni in-memory / 7 lat archive (RODO + KPK + KC).
- ADR rezerwacja: kazdy duza zmiana decyzyjna potrzebuje ADR proposed przed implementacja (NIE post-hoc).
- Widoczne dla modelu = zapisane w dzienniku. Cokolwiek trafia do zapytania modelu (system prompt, wynik narzedzia, fragment akt, wstrzykniety kontekst, wynik konektora MCP) musi dac sie odtworzyc z dziennika sesji /
audit_log. Nowy input widoczny dla modelu bez nowego zdarzenia w dzienniku = finding. Test odwrotny: czy z samego dziennika da sie zrekonstruowac, co model widzial w tej turze? Jesli nie, art. 12 jest deklaracja, nie mechanizmem. Wzorzec z inwariantu "model-visible <=> logged" (deepseek-harness, MIT, pattern-only).
Komendy:
rg -n "auditLog|writeAuditEntry|recordDecision" lib/audit/ lib/services/
rg -n "anonymize|piiDetect|let-it-be" lib/pii/ lib/services/
rg -n "PESEL|NIP|REGON" README.md docs/ aktualnosci/ # zero hits expected w public
rg -n "messages\.push|\.append\(\{.*role|systemPrompt|system_prompt" lib/ src/ # kazde miejsce = czy ma zdarzenie w dzienniku?
14. Konstytucja drift - per AGENTS.md
Po gh repo create / push nowego komponentu PUBLICZNEGO uruchom 7-stopniowa checkliste catchup (zasada hub kuratorski MateMatic - kod wyprzedza dokumentacje). Ten skill sprawdza w PR diffe:
Checks:
- Nowy komponent zarejestrowany w main? README repo update? AGENTS.md update? CHANGELOG entry?
- Konstytucja PATRON wymaga SEMVER bump przy nowym ADR przyjetym (rezerwacja chronologii przy sesjach rownoleglych).
- Errata: jesli ADR rodzic mial nazwe tabeli/funkcji ktora sie zmienila, sprawdz literal cytat w nowych ADR (propagacja erraty przez literal cytat).
Final pass: shape the report
Findings w 3 buckets:
Blocker (MUST fix przed merge):
- Missing org scope na request-reachable lookup (sekcja 2)
- Route bez auth bez deliberate public auth mechanism (sekcja 1)
- Webhook bez signature verification lub significant unrelated work przed verification (sekcja 8)
- Migracja bez safe backfilla lub meaningful downgrade (sekcja 6)
- UI bypassuje generated SDK dla internal API calls (sekcja 9)
- Secrets/PII klienta logowane (sekcja 10, 13)
- Operacja decyzyjna BEZ audit_log entry (sekcja 13)
- Input widoczny dla modelu, ktorego nie da sie odtworzyc z dziennika sesji (sekcja 13)
- Generowanie LLM bez citation-grounding lub pisma docx bez wewnetrznego pipeline QA (sekcja 13)
- Dane z realnych akt w public artefactach (sekcja 13)
Should-fix (mocno polecane):
- Cached state mutowany bez worker sync (sekcja 4)
- JSON vs JSONB inconsistency (sekcja 6)
- Response schema leak internal identifiers (sekcja 12)
- Backend API zmienione bez client regen tam gdzie UI konsumuje (sekcja 9)
- Test path moze hang indefinitely (sekcja 11)
- MCP tool reimplementuje auth zamiast
authenticate_mcp_request() (sekcja 7)
- Drift dokumentacji vs kod (sekcja 14)
Nit (drobne):
- Naming inconsistencies
- Minor convention drift
- Low-risk schema / report-shape cleanup
Cytuj plik:linia dla kazdego finding. Pomin to co formatter/linter/IDE i tak zlapie chyba ze laczy sie z jednym z repo-specific risks powyzej.
Anti-pattern w sposobie review
- NIE pisanie generic FastAPI/Next.js comments - tylko repo-specific
- NIE polegaj na statycznych allowlistach z tego pliku - czytaj aktualny repo
- NIE marudz na styl bez
repo-specific risk connection
- NIE chwalenie w findings - tylko problemy
- NIE post-merge findings (znajdzeli sie zalozenia ze mergowali bo ja przepuscilem) - read przed merge
Walidowane na
- dograh-hq/dograh v1.31.0 review-pr.md (BSD-2, 286 linii) - source pattern
- PATRON ADR-0033 (audit_log) + ADR-0028 (mcp-security-gateway) - 401/406 testow, 3 rundy senior review, errata z parent ADR (sesja 2026-05-24)
Linki
1---2name: matematic-patron-pr-review-pl3description: Recenzent PR/diffow dla PATRONa - polski LegalTech AI agent dla kancelarii. Wylapuje regresje specyficzne dla repo PATRON ktorych nie zlapie generyczny lint - org scoping multi-tenant, authless routes, niespodzianki w migracjach SQLite/Postgres, bezposredni SQL poza warstwa db, brak worker sync w cache, UI bez generated SDK, sekrety w logach, regresje audit_log, brak grounding cytatow, AI Act art. 12 record-keeping. Format findings file:line -> problem -> correct pattern, 3 buckets Blocker/Should-fix/Nit. Uzywaj gdy - recenzja PR/diff PATRON przed merge, code review pre-commit, audyt zmian w mcp-security-gateway/audit_log/ring-policy/auth, review zmian w MCP serverach matematicsolutions/*, weryfikacja czy nowy kod nie wprowadza wyciekow danych klienta kancelarii (RODO/tajemnica adwokacka), audyt drift dokumentacji vs kod. Trigger - "marko review PR", "code review PATRON", "audyt diff", "review tej zmiany", "sprawdz PR", "czy bezpiecznie merge", "PR audit", "security review PATRON", "blast radius zmiany".4license: Apache-2.05---67# matematic-patron-pr-review-pl89Recenzent PR/diffow PATRON - polskiego LegalTech AI agenta dla kancelarii. Cherry-pick struktury z [dograh v1.31.0 review-pr](https://github.com/dograh-hq/dograh/blob/main/.agents/skills/review-pr/SKILL.md) (BSD-2, 286 linii), zaadaptowane pod kontekst MateMatic.1011**Komplementarny do:**12- Wewnetrzny pipeline QA MateMatic dla tresci PL (artykuly, copy LI, BW) - ocena czytelnosci i poprawnosci. Ten skill ocenia **diff kodu**.13- [matematic-konstytucja-ai](../matematic-konstytucja-ai) (w tym hubie) - dokument governance dla klienta. Ten chroni kod produktu.14- Self-review pre-commit (6 zasad MateMatic) - poprzedza ten skill, sprawdza ogolne, ten skill nad nimi sprawdza repo-specific risks.1516## Kiedy uzywac1718- Recenzja PR przed merge do `main` w repo PATRON / KGLF / matematicsolutions MCP serwery19- Pre-commit audit wlasnego diffu w PATRONie20- Audyt zmian w komponentach krytycznych: mcp-security-gateway, audit_log, ring-policy, auth21- Po duzej refaktoryzacji - sweep pod katem regresji22- Przed pushem do `origin` po sesji 3+ commitow2324## Glowne tryby awarii w repo PATRON25261. **Multi-tenant - brak org scoping** na request-reachable read/write (kancelaria A widzi sprawe kancelarii B)272. **Authless route lub websocket** - silently public endpoint283. **Webhook bez signature verification** lub trust w unsigned fields294. **SQL pisany poza `lib/db/*_client.ts`** - inkasacja warstwy305. **Cache per-worker bez worker sync** - stale state w innych procesach316. **UI bypassuje generated SDK** - direct `fetch('/api/v1/...')` zamiast typed client327. **Migracja niebezpieczna na produkcji** - NOT NULL bez backfilla, brak downgrade()338. **MCP tool reimplementuje auth** zamiast `authenticate_mcp_request()` (patrz [matematic-mcp-fastmcp-instructions-pl](../matematic-mcp-fastmcp-instructions-pl) w tym hubie)349. **PII/cytat prawniczy w logach** - naruszenie RODO + tajemnica adwokacka (art. 6 ust. 1 PrAdw + art. 3 ust. 3 RadcPrU)3510. **Brak audit_log entry** dla operacji decyzyjnej (AI Act art. 12 record-keeping)3637## Jak prowadzic review38391. Pobierz diff:40 - GitHub PR: `gh pr diff <N>` lub `gh pr view <N> --json files,additions,deletions`41 - Local branch: `git diff origin/main...HEAD`42 - Pre-commit: `git diff HEAD`432. Bucketuj zmienione pliki do sekcji nizej443. **Czytaj aktualny kod jako source of truth** przed finalizacja findings:45 - `AGENTS.md` (root + per-package) - org scoping i worker sync46 - Dotknieci modele, db clients, routes, services, migrations474. Run TYLKO sekcje istotne dla zmienionych plikow485. Raportuj `<plik>:<linia> -> <problem> -> <correct pattern>`4950## Freshness rule (KRYTYCZNE)5152Traktuj ten plik jako **review policy + navigation**, NIE jako frozen inventory.5354- Jesli aktualne repo PATRON klocy sie z tym skillem, ufaj repo i wymien drift jako problem.55- NIE polegaj na statycznych allowlistach ani konkretnych liniach z tego pliku.56- Recenzuj **kod w PR i aktualnym repo**, nie ten plik.5758## Mapa: sciezka w diffie -> sekcje do uruchomienia5960| Ścieżka w diffie | Sekcje |61|---|---|62| `app/routes/*.ts`, `apps/api/routes/` | 1, 2, 8 |63| `lib/db/*_client.ts`, `lib/db/schema.ts`, `lib/db/models.ts` | 2, 3 |64| `lib/services/**/*.ts`, `apps/api/services/` | 2, 3, 4 |65| `lib/tasks/*.ts`, `apps/worker/` | 2, 3, 5 |66| `db/migrations/*.sql`, `lib/db/migrations/` | 6 |67| `mcp-servers/**`, `matematicsolutions/mcp-*` | 1, 2, 7, kanon MCP (patrz `matematic-mcp-fastmcp-instructions-pl`) |68| `apps/ui/**`, `apps/dashboard/**` | 9 |69| `lib/constants.ts`, anything `process.env` outside lib/constants | 10 |70| `tests/**`, `__tests__/**` | 11 |71| `lib/schemas/*.ts`, `lib/dto/*.ts` | 12 |72| `lib/audit/**`, `lib/pii/**`, `lib/anonimizacja/**` | 13 (MateMatic-specific) |7374---7576## 1. Route authentication7778Brak globalnego middleware auth w PATRON. Kazda trasa deklaruje swoja auth.7980Zaleznosci auth z `lib/auth/depends.ts`:81- `getUser` (user kancelarii w organizacji)82- `getUserWs` (websocket - kancelaria realtime)83- `getSuperuser` (root MateMatic, NIE klient kancelaria)84- `requireRing(N)` (ring-policy ADR-0027) - dla decyzji authorization8586Checks:87- Nowy `@router.<verb>(...)` bez auth dependency = silently public. Finding chyba ze plik ustanawia public auth pattern (np. webhook signed, public token).88- `getUser` na impersonation / cross-org / global reporting -> powinno byc `getSuperuser`.89- Route reimplementujaca Bearer/X-API-Key parsing zamiast shared dependency = finding.90- WebSocket bez `Depends(getUserWs)` i bez public-token flow = finding.91- Tightening CORS do fixed origin list potrzebuje strong justification - PATRON polega na cross-origin embedding (widget kancelarii).92- Nowy endpoint zwracajacy dane kancelarii BEZ wpiecia w ring-policy (`requireRing(2)+`) = finding.9394Komendy:95```bash96rg -n "Depends\((getUser|getUserWs|getSuperuser|requireRing)" app/routes/ apps/api/97rg -n "@router\.(get|post|put|delete|patch|websocket)" app/routes/98```99100---101102## 2. Organization scoping (THE CROSS-TENANT RULE - PRIORYTET #1)103104NAJWAZNIEJSZA regula w PATRON. Kancelaria A NIGDY nie widzi danych kancelarii B. Kazdy request-reachable read/write resourca org-scoped MUSI filtrowac/walidowac przez `organization_id`.105106Polega na: `AGENTS.md` canonical summary + ADR-0027 ring-policy.107108Determinacja scope:109- **Direct scope**: model ma `organization_id` (cases, documents, prompts, agents)110- **Indirect scope**: model siega org przez parent FK (e.g. comments -> document -> org)111- Legacy spelling moze istniec w starych migracjach (`org_id`, `tenant_id`), ale **nowy kod uzywa `organization_id`**112113Checks:114- Kazdy `*ById(...)` / `getXById(...)` w route handler = suspicious. Jesli request-reachable i unscoped = finding.115- Nowe `list*` / `get*` endpointy filtruja w SQL (`WHERE organization_id = ?`), NIE w TS po `.all()`.116- Jesli request pisze FK do innego org-scoped resourca, route MUSI najpierw fetch target row z `user.selectedOrganizationId` i odrzucic jesli nie nalezy do org.117- Services wolane z routes preserva scoping. Drop `organization_id` w DB client call = trace caller.118- **Background tasks NIE dostaja org context for free.** Musza reload parent row i derive org z tego.119- **Webhooki derive org z signed identifier**, NIE z caller-supplied body fields `organization_id`.120- Nowy kod uzywa kanoniczne `organizationId`, nie `orgId`, `tenantId`, `organisationId`.121122Komendy:123```bash124rg -n "ById\(" app/routes/ lib/services/ apps/worker/125rg -n "dbClient\.get\w+\(" app/routes/ lib/services/126rg -n "organizationId|selectedOrganizationId|requireRing" app/routes/ lib/services/ apps/worker/ lib/db/127```128129---130131## 3. DB query layering132133Production SQL nalezy do `lib/db/*_client.ts`. Routes, services, tasks WOLAJA db client methods, NIE pisza Drizzle/SQL bezposrednio.134135Checks:136- `db.select`, `db.update`, `db.delete`, `db.insert`, `sql\`\``, `prepare(`, `transaction(` w `app/routes/`, `lib/services/`, `apps/worker/` = finding.137- `lib/services/adminUtils/` to wyjatek - NIE jest template'em dla production.138- Session lifecycle w db client.139- Nowe params db client uzywaja kanoniczne `organizationId`.140141Komendy:142```bash143rg -n "(db\.select|db\.update|db\.delete|db\.insert|sql\`)" app/routes/ lib/services/ apps/worker/144```145146---147148## 4. Worker sync - multi-process state coherence149150Production PATRON ma multi-worker. Per-process mutable caches stale unless broadcast.151152Checks:153- Nowy module-level / class-level mutable cache pisany przez endpoint potrzebuje WorkerSyncManager broadcast path.154- Local invalidation alone NIE wystarcza jesli inni workerzy moga jeszcze serwowac stale state.155- Jesli PR wprowadza nowy cached object, diff powinien zawierac:156 - broadcast call157 - event type / signal definition158 - handler registration ktory reload fresh state159160---161162## 5. Background tasks / queue workers163164Checks:165- User-triggered enqueue paths waliduja org ownership przed enqueue.166- Tasks ktore akceptuja ID i reload row musza derive org z tego row, NIE assume shared context.167- Tasks idempotentne lub explicit retry-safe.168- Tylko real task entrypoints w `apps/worker/queue.ts::routes`.169- Secret logging rules z sekcji 10 dotycza tu.170171---172173## 6. Migrations (`db/migrations/*.sql` lub Drizzle migrations)174175Checks:176- `up` i `down` istnieja i sa meaningfully reversible chyba ze zmiana naprawde nie da sie cofnac.177- `NOT NULL` column do zaludnionej tabeli potrzebuje safe default lub backfilla przed constraint.178- Tightening nullable -> NOT NULL potrzebuje backfilla PRZED `ALTER COLUMN ... SET NOT NULL`.179- Nowe JSON columny match JSON/JSONB convention tabeli.180- Big backfills w migracji - pytaj. Czesto naleza out-of-band.181- Indexy na duzych tabelach (kancelarii produkcyjnych) potrzebuja concurrent-safe handling (`CREATE INDEX CONCURRENTLY`).182- NIE traktuj historical migration naming jako finding sam w sobie. Recenzuj zmieniana migracje, nie stara prose.183184---185186## 7. MCP servers (`mcp-servers/**`, `matematicsolutions/mcp-*`)187188Reguly z [matematic-mcp-fastmcp-instructions-pl](../matematic-mcp-fastmcp-instructions-pl) - 8 elementow kanonu.189190Checks:191- Nowe tools uzywaja `authenticateMcpRequest()` (lub Pythonowy `authenticate_mcp_request()`), NIE reimplementuja API-key validation.192- Nowe tool DB lookups preserva org scoping jak REST routes.193- Tools wolajace external URLs waliduja URL i konsideruja SSRF.194- Nowe MCP tool wymieniony w `instructions` ma istniec w registry (drift test).195- `errorCode` zwracane przez tool sa w docstring tool (drift test).196- ToolAnnotations dla read-only (`readOnlyHint=true`) dla tooli ktore nie mutuja.197198---199200## 8. Telephony / webhook handlers201202Checks:203- Nowy provider webhook flow implementuje `verifyInboundSignature()` lub provider equivalent.204- Minimal pre-verification work moze byc wymagana zeby zidentyfikowac candidate config, ALE route NIE robi unrelated workflow/user/stateful work przed verification.205- Org derivation z provider identifiers walidowanych przez webhook auth flow.206- Webhook NIE ufa raw body `organizationId`.207- Jesli webhook referencuje numer telefonu, walidacja ze numer istnieje dla derived org.208209---210211## 9. UI (`apps/ui/**`, `apps/dashboard/**`) - generated SDK only212213Frontend rozmawia z backendem przez `apps/ui/src/client/` (generated typed SDK).214215Checks:216- `fetch('/api/v1/...')` lub `fetch(\`${backendUrl}/api/v1/...\`)` w app code = finding chyba ze aktualny kod udowadnia narrow exception.217- Hardcoded backend URLs = finding.218- Manualna konstrukcja `Authorization` header w zwyklych komponentach = finding (auth injected centrally).219- SDK calls firowane przed auth state ready = finding.220- Local interfaces duplikujace generated types = finding.221- Backend API shape zmienione + UI konsumuje = `apps/ui/src/client/` powinno tez sie zmienic.222223---224225## 10. Logging, secrets, constants226227Checks:228- Nowy kod uzywa shared logger (np. `pino` z PII masking), NIE `console.log`.229- Nowy `process.env.X` poza `lib/constants.ts` = finding.230- NIE logujemy: API keys, bearer tokens, credentials, full webhook bodies, **PII klienta kancelarii (PESEL, NIP, imiona, sygnatury aktualnych spraw)**.231- Common offender shapes:232 - `logger.info(\`config: ${JSON.stringify(config)}\`)`233 - `logger.debug(requestBody)`234 - Logging raw config / user configuration rows235236---237238## 11. Tests (`tests/**`, `__tests__/**`)239240Checks:241- Async waits uzywaja bounded timeout (`pTimeout`, `setTimeout race`), NIE `while (!done)`.242- Tests run against `.env.test`, NIE `.env`.243- Integration tests NIE neutered przez mockowanie zeby test passed - musza hit prawdziwy testowy DB.244- Tests zalezne od mutable shared DB state across test cases = suspicious.245246---247248## 12. Schemas (`lib/schemas/*.ts`, `lib/dto/*.ts`)249250Checks:251- Nowe response schemas NIE expose internal FKs / IDs chyba ze caller naprawde potrzebuje.252- Request schemas akceptujace org-scoped FK values = trigger do inspekcji corresponding route pod katem section 2 ownership validation.253254---255256## 13. PATRON-specific - PII, audit_log, AI Act art. 12257258**Tej sekcji NIE ma w dograh** - to MateMatic-specific dla legal AI.259260Checks:261- Operacja decyzyjna (klasyfikacja dokumentu, rekomendacja, generowanie pisma, anonimizacja) MUSI zapisac do `audit_log` (ADR-0033). Brak entry = finding (AI Act art. 12 record-keeping).262- PII detection / anonimizacja inline PRZED storage uzytkowych logow ([matematic-anonimizacja-pl](https://github.com/matematicsolutions/matematic-anonimizacja-pl) jako pre-storage filter). Bypass = finding.263- Cytat z orzeczenia / ustawy w odpowiedzi LLM musi przejsc [citation-grounding-pl](../citation-grounding-pl) (mechaniczna weryfikacja string-match). Jesli kod generuje odpowiedz LLM bez tego layera = finding.264- Pisma procesowe MUSZA przejsc wewnetrzny pipeline QA MateMatic (anti-slop PL + senior review min 2 rundy) przed docx. Kod generujacy .docx bez tej walidacji = finding.265- Dane z prawdziwych akt klienta (kwoty, sygnatury, inicjaly) w README/aktualnosci/post LI = czerwona linia tajemnicy adwokackiej (art. 6 ust. 1 PrAdw) / radcowskiej (art. 3 ust. 3 RadcPrU). Grep przed push.266- Nowy retention policy: dane klienta kancelarii max 90 dni in-memory / 7 lat archive (RODO + KPK + KC).267- ADR rezerwacja: kazdy duza zmiana decyzyjna potrzebuje ADR proposed przed implementacja (NIE post-hoc).268- **Widoczne dla modelu = zapisane w dzienniku.** Cokolwiek trafia do zapytania modelu (system prompt, wynik narzedzia, fragment akt, wstrzykniety kontekst, wynik konektora MCP) musi dac sie odtworzyc z dziennika sesji / `audit_log`. Nowy input widoczny dla modelu bez nowego zdarzenia w dzienniku = finding. Test odwrotny: czy z samego dziennika da sie zrekonstruowac, co model widzial w tej turze? Jesli nie, art. 12 jest deklaracja, nie mechanizmem. Wzorzec z inwariantu "model-visible <=> logged" (deepseek-harness, MIT, pattern-only).269270Komendy:271```bash272rg -n "auditLog|writeAuditEntry|recordDecision" lib/audit/ lib/services/273rg -n "anonymize|piiDetect|let-it-be" lib/pii/ lib/services/274rg -n "PESEL|NIP|REGON" README.md docs/ aktualnosci/ # zero hits expected w public275rg -n "messages\.push|\.append\(\{.*role|systemPrompt|system_prompt" lib/ src/ # kazde miejsce = czy ma zdarzenie w dzienniku?276```277278---279280## 14. Konstytucja drift - per AGENTS.md281282Po `gh repo create` / push nowego komponentu PUBLICZNEGO uruchom 7-stopniowa checkliste catchup (zasada hub kuratorski MateMatic - kod wyprzedza dokumentacje). Ten skill sprawdza w PR diffe:283284Checks:285- Nowy komponent zarejestrowany w main? README repo update? AGENTS.md update? CHANGELOG entry?286- Konstytucja PATRON wymaga SEMVER bump przy nowym ADR przyjetym (rezerwacja chronologii przy sesjach rownoleglych).287- Errata: jesli ADR rodzic mial nazwe tabeli/funkcji ktora sie zmienila, sprawdz literal cytat w nowych ADR (propagacja erraty przez literal cytat).288289---290291## Final pass: shape the report292293Findings w 3 buckets:294295**Blocker** (MUST fix przed merge):296- Missing org scope na request-reachable lookup (sekcja 2)297- Route bez auth bez deliberate public auth mechanism (sekcja 1)298- Webhook bez signature verification lub significant unrelated work przed verification (sekcja 8)299- Migracja bez safe backfilla lub meaningful downgrade (sekcja 6)300- UI bypassuje generated SDK dla internal API calls (sekcja 9)301- Secrets/PII klienta logowane (sekcja 10, 13)302- Operacja decyzyjna BEZ audit_log entry (sekcja 13)303- Input widoczny dla modelu, ktorego nie da sie odtworzyc z dziennika sesji (sekcja 13)304- Generowanie LLM bez citation-grounding lub pisma docx bez wewnetrznego pipeline QA (sekcja 13)305- Dane z realnych akt w public artefactach (sekcja 13)306307**Should-fix** (mocno polecane):308- Cached state mutowany bez worker sync (sekcja 4)309- JSON vs JSONB inconsistency (sekcja 6)310- Response schema leak internal identifiers (sekcja 12)311- Backend API zmienione bez client regen tam gdzie UI konsumuje (sekcja 9)312- Test path moze hang indefinitely (sekcja 11)313- MCP tool reimplementuje auth zamiast `authenticate_mcp_request()` (sekcja 7)314- Drift dokumentacji vs kod (sekcja 14)315316**Nit** (drobne):317- Naming inconsistencies318- Minor convention drift319- Low-risk schema / report-shape cleanup320321Cytuj `plik:linia` dla kazdego finding. Pomin to co formatter/linter/IDE i tak zlapie chyba ze laczy sie z jednym z repo-specific risks powyzej.322323## Anti-pattern w sposobie review324325- NIE pisanie generic FastAPI/Next.js comments - tylko repo-specific326- NIE polegaj na statycznych allowlistach z tego pliku - czytaj aktualny repo327- NIE marudz na styl bez `repo-specific risk connection`328- NIE chwalenie w findings - tylko problemy329- NIE post-merge findings (znajdzeli sie zalozenia ze mergowali bo ja przepuscilem) - read przed merge330331## Walidowane na332333- [dograh-hq/dograh](https://github.com/dograh-hq/dograh) v1.31.0 review-pr.md (BSD-2, 286 linii) - source pattern334- PATRON ADR-0033 (audit_log) + ADR-0028 (mcp-security-gateway) - 401/406 testow, 3 rundy senior review, errata z parent ADR (sesja 2026-05-24)335336## Linki337338- [matematic-mcp-fastmcp-instructions-pl](../matematic-mcp-fastmcp-instructions-pl) - kanon MCP (sekcja 7)339- [citation-grounding-pl](../citation-grounding-pl) - anti-halucynacja cytatu (sekcja 13)340- [legal-ai-audit-bundle](../legal-ai-audit-bundle) - audit AI Act art. 12 (sekcja 13)341- [matematic-anonimizacja-pl](https://github.com/matematicsolutions/matematic-anonimizacja-pl) - PII anonimizacja (sekcja 13)342- [dograh-hq/dograh](https://github.com/dograh-hq/dograh) - source pattern (BSD-2)