T9: Person title/pwzNumber fields [checkpoint]
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
**Historia (poprzedni plan, superseded)**
|
||||
- Pierwsza wersja planu była jednoskryptowa (Python: `requests` + BeautifulSoup, ładowanie przez `neo4j` driver) i ograniczona do województwa podlaskiego. Zastąpiona przez ten plan: **wielowojewódzki**, **warstwowy**, jako aplikacja **Java 21 + Maven + Spring Shell**, gdzie każda warstwa to osobna komenda CLI.
|
||||
- Wkład starego planu wchłonięty tutaj: tabela źródeł/provenance (sekcja 3→ obecnie 4.6 + 7), zapytania walidacyjne i raport nakładek (→ 5.6), obsługa przypadków brzegowych i rate-limitu (→ 7), lista produktów i checklista wykonawcza (→ 9, 10). Pseudokod Pythona porzucony — logikę realizuje kod Javy warstw `ingest`/`load`.
|
||||
- `PLAN2.md` (delta) wchłonięty tutaj: rozszerzenie `Person` o `title`/`pwzNumber` (→ 2, 4.7), nowe encje `Organization`/`Company` z powiązaniami po KRS/NIP/CEIDG (→ 2, 4.8, 5.2), nowe zadania kolejki agenta (→ T9–T13). Plik `PLAN2.md` usunięty po scaleniu.
|
||||
- Kolejka §11 przepisana pod konkretny model wykonawczy: **Qwen-3.6-35B-A3B** (MoE, ~3B aktywnych parametrów na token, mały kontekst efektywny). Reguły atomowości zadań i zakaz planowania (już obecne w poprzedniej wersji dla „małego lokalnego modelu") pozostają — dopisano jawne odniesienie do tego modelu, by przyszłe zadania kalibrować pod jego ograniczenia kontekstu i skłonność do zmyślania API.
|
||||
|
||||
---
|
||||
|
||||
@@ -89,9 +91,57 @@ Jeden schemat dla **wszystkich** województw. Plik `canonical/<voivodeship>.json
|
||||
"fullName": "Jan Kochanowicz",
|
||||
"displayName": "prof. dr hab. n. med. Jan Kochanowicz", // z tytułami, jak w źródle
|
||||
"titles": ["prof.", "dr hab.", "n. med."],
|
||||
"title": "prof. dr hab. n. med.", // tytuł skondensowany (jedno pole, do wyświetlania obok fullName)
|
||||
"pwzNumber": "1234567", // Prawo Wykonywania Zawodu, z rejestr.nil.org.pl; null gdy nieznaleziony
|
||||
"sourceUrls": ["https://uskwb.pl/dyrekcja-szpitala/"]
|
||||
}
|
||||
],
|
||||
"organizations": [ // NGO/fundacje/stowarzyszenia powiązane z osobami przez KRS
|
||||
{
|
||||
"id": "org:fundacja-xyz",
|
||||
"name": "Fundacja XYZ",
|
||||
"krs": "0000123456",
|
||||
"nip": null,
|
||||
"sourceUrls": ["https://ems.ms.gov.pl/..."]
|
||||
}
|
||||
],
|
||||
"companies": [ // spółki/działalności gospodarcze powiązane z osobami
|
||||
{
|
||||
"id": "company:abc-sp-zoo",
|
||||
"name": "ABC sp. z o.o.",
|
||||
"krs": "0000654321",
|
||||
"nip": "1234567890",
|
||||
"ceidgId": null,
|
||||
"sourceUrls": ["https://wyszukiwarka-krs.ms.gov.pl/..."]
|
||||
}
|
||||
],
|
||||
"personOrganizationLinks": [ // osoba ↔ organizacja, dopasowanie po KRS
|
||||
{
|
||||
"personId": "person:jan-kochanowicz",
|
||||
"organizationId": "org:fundacja-xyz",
|
||||
"roleLabel": "Prezes Zarządu",
|
||||
"basis": "KRS", // klucz, po którym dopasowano powiązanie
|
||||
"sourceUrls": ["https://ems.ms.gov.pl/..."]
|
||||
}
|
||||
],
|
||||
"organizationLinks": [ // organizacja ↔ organizacja, po KRS/NIP (np. wspólny adres/zarząd)
|
||||
{
|
||||
"fromOrganizationId": "org:fundacja-xyz",
|
||||
"toOrganizationId": "org:inna-fundacja",
|
||||
"basis": "NIP", // KRS | NIP
|
||||
"note": "wspólny adres siedziby",
|
||||
"sourceUrls": ["https://ems.ms.gov.pl/..."]
|
||||
}
|
||||
],
|
||||
"personCompanyLinks": [ // osoba ↔ firma, po KRS/CEIDG/NIP
|
||||
{
|
||||
"personId": "person:jan-kochanowicz",
|
||||
"companyId": "company:abc-sp-zoo",
|
||||
"roleLabel": "Wspólnik",
|
||||
"basis": "KRS", // KRS | CEIDG | NIP
|
||||
"sourceUrls": ["https://wyszukiwarka-krs.ms.gov.pl/..."]
|
||||
}
|
||||
],
|
||||
"affiliations": [ // przynależność partyjna/komitetowa osoby
|
||||
{
|
||||
"personId": "person:karol-pilecki",
|
||||
@@ -133,8 +183,10 @@ Jeden schemat dla **wszystkich** województw. Plik `canonical/<voivodeship>.json
|
||||
|
||||
**Uwagi projektowe:**
|
||||
- `id` osoby jest generowane deterministycznie z znormalizowanego imienia i nazwiska (patrz normalizacja) — to podstawa deduplikacji **między szpitalami i województwami** (np. osoba zasiadająca w radach kilku szpitali).
|
||||
- Enumy (`legalForm`, `roleType`, `mandateType`, `confidence`, `status`) są zamknięte i wspólne dla wszystkich województw — to gwarantuje uwspólniony format.
|
||||
- Enumy (`legalForm`, `roleType`, `mandateType`, `confidence`, `status`) są zamknięte i wspólne dla wszystkich województw — to gwarantuje uwspólniony format. Nowy zamknięty enum `LinkBasis` (`KRS`, `NIP`, `CEIDG`) opisuje klucz dopasowania powiązań organizacja/firma.
|
||||
- Pola `note` i `confidence` przenoszą metadane jakościowe z materiału roboczego (kluczowe dla kontekstu dziennikarskiego).
|
||||
- `id` organizacji/firmy jest slugiem z nazwy + (gdy dostępny) KRS w nawiasie logiki dedupu — dwie różne organizacje o tej samej nazwie, ale różnym KRS, **nie są scalane** (analogicznie do zasady dla `Person` w 4.3 pkt 4).
|
||||
- `pwzNumber` bywa `null` — brak trafienia w rejestr.nil.org.pl to nie błąd, tylko luka odnotowywana w `ingest-report.json` (patrz 4.7).
|
||||
|
||||
---
|
||||
|
||||
@@ -152,6 +204,7 @@ Jeden schemat dla **wszystkich** województw. Plik `canonical/<voivodeship>.json
|
||||
| CSV (raporty) | `commons-csv` |
|
||||
| Testy | JUnit 5, Testcontainers (`neo4j` container) do testów warstwy ładowania |
|
||||
| Konteneryzacja Neo4j | Docker (`neo4j:5`), Bolt na `7687`, UI na `7474` |
|
||||
| Rejestry zewnętrzne | rejestr.nil.org.pl (PWZ, formularz HTML — brak API), wyszukiwarka-krs.ms.gov.pl / api-krs (KRS), CEIDG API (dane.biznes.gov.pl) |
|
||||
|
||||
### Szkielet projektu Maven
|
||||
```
|
||||
@@ -163,14 +216,18 @@ szpitale-graph/
|
||||
│ ├── model/ # rekordy modelu kanonicznego
|
||||
│ │ ├── CanonicalDataset.java
|
||||
│ │ ├── Hospital.java Person.java Affiliation.java Role.java Mandate.java
|
||||
│ │ └── enums/ (LegalForm, RoleType, MandateType, Confidence, ...)
|
||||
│ │ ├── Organization.java Company.java PersonOrganizationLink.java OrganizationLink.java PersonCompanyLink.java
|
||||
│ │ └── enums/ (LegalForm, RoleType, MandateType, Confidence, LinkBasis, ...)
|
||||
│ ├── ingest/ # WARSTWA 1
|
||||
│ │ ├── IngestCommand.java # @ShellComponent — komenda `ingest`
|
||||
│ │ ├── source/ # źródła per-województwo
|
||||
│ │ │ ├── VoivodeshipSource.java # interfejs: List<RawRecord> fetch()
|
||||
│ │ │ ├── MarkdownRegistrySource.java# parser materiałów typu research-*.md
|
||||
│ │ │ ├── HtmlScraperSource.java # jsoup: strony szpitali/BIP
|
||||
│ │ │ └── PkwSource.java # weryfikacja afiliacji w PKW 2024
|
||||
│ │ │ ├── PkwSource.java # weryfikacja afiliacji w PKW 2024
|
||||
│ │ │ ├── PwzRegistrySource.java # uzupełnienie pwzNumber z rejestr.nil.org.pl (4.7)
|
||||
│ │ │ ├── KrsSource.java # organizacje/firmy + powiązania po KRS (4.8)
|
||||
│ │ │ └── CeidgSource.java # powiązania osoba↔firma po CEIDG/NIP (4.8)
|
||||
│ │ ├── normalize/
|
||||
│ │ │ ├── NameNormalizer.java # diakrytyki, tytuły, wielkość liter, slug
|
||||
│ │ │ ├── PartyNormalizer.java # mapowanie nazw partii/komitetów
|
||||
@@ -203,6 +260,9 @@ Implementacje (wybierane po fladze/konfiguracji):
|
||||
- **`MarkdownRegistrySource`** — parsuje istniejące materiały robocze w formacie tabel Markdown (jak `research-podlaskie.md`). To ścieżka startowa: podlaskie już mamy. Kolejne województwa dokładamy jako `research-<voiv>.md` (patrz sekcja 4.6 — generowane skillem deep-research).
|
||||
- **`HtmlScraperSource`** — `HttpClient` + jsoup do stron szpitali (dyrekcja) i BIP (rady). Rate-limiting + retry z backoffem, `User-Agent`, poszanowanie `robots.txt`.
|
||||
- **`PkwSource`** — kontrola krzyżowa afiliacji radnych w `samorzad2024.pkw.gov.pl` (podnosi `confidence`).
|
||||
- **`PwzRegistrySource`** — uzupełnia `pwzNumber` osoby z `rejestr.nil.org.pl` (formularz imię+nazwisko, patrz 4.7).
|
||||
- **`KrsSource`** — wyszukuje organizacje/firmy powiązane z osobą po KRS (patrz 4.8).
|
||||
- **`CeidgSource`** — kontrola krzyżowa działalności gospodarczych osoby po CEIDG/NIP (patrz 4.8).
|
||||
|
||||
Rejestr źródeł spina wszystkie województwa; brak konfiguracji dla danego województwa = pomijane z ostrzeżeniem w logu (żadnych cichych luk).
|
||||
|
||||
@@ -238,6 +298,27 @@ Wynik zapisujemy jako `research-mazowieckie.md`. Skalowanie na wszystkie wojewó
|
||||
|
||||
**Granica odpowiedzialności:** deep-research **znajduje i weryfikuje źródła** (etap dziennikarsko-badawczy, wymaga oceny człowieka przed publikacją, zwłaszcza dla oznaczeń `NIEZWERYFIKOWANA`). Kod Javy (warstwa 1) **nie prowadzi researchu** — jedynie deterministycznie normalizuje gotowy materiał `.md` do modelu kanonicznego. Ten podział utrzymuje warstwę 1 testowalną i powtarzalną, a odkrywanie źródeł — audytowalne i cytowane.
|
||||
|
||||
### 4.7. Uzupełnienie numeru PWZ — `PwzRegistrySource`
|
||||
|
||||
`rejestr.nil.org.pl` (Naczelna Izba Lekarska) udostępnia wyszukiwarkę lekarzy **wyłącznie jako formularz HTML** (imię + nazwisko), bez publicznego API. Wzbogacenie działa jako osobny krok w `ingest`, **po** normalizacji osób (potrzebuje `fullName`):
|
||||
|
||||
1. Dla każdej osoby o `titles` sugerujących zawód medyczny (`dr`, `dr n. med.`, `prof.`, `lek.`, itp. — heurystyka w `PwzRegistrySource`, nie każda osoba w radzie jest lekarzem) wyślij zapytanie z `fullName`.
|
||||
2. **Wiele trafień** (częste nazwiska) → `pwzNumber = null`, `note = "wieloznaczne trafienie NIL, wymaga ręcznej weryfikacji"`, wpis w `ingest-report.json`.
|
||||
3. **Brak trafienia** → `pwzNumber = null`, brak `note` (osoba może nie być lekarzem — to nie błąd).
|
||||
4. Rate-limiting jak dla `HtmlScraperSource` (4.2/7) — to ten sam serwis żywy, nie plik `.md`.
|
||||
|
||||
**Granica odpowiedzialności:** to wzbogacenie jest **deterministyczne i automatyczne** (1:1 zapytanie→wynik po nazwisku), inaczej niż `deep-research` (4.6) — nie wymaga oceny dziennikarskiej, tylko technicznej weryfikacji przy wieloznaczności.
|
||||
|
||||
### 4.8. Organizacje i firmy — `KrsSource` / `CeidgSource`
|
||||
|
||||
Rozszerzenie modelu o encje `Organization` (fundacje, stowarzyszenia) i `Company` (spółki, działalności gospodarcze) powiązane z osobami z organów szpitali — cel: ujawnić potencjalne konflikty interesów.
|
||||
|
||||
1. **`KrsSource`** — dla każdej osoby: wyszukanie w KRS (`wyszukiwarka-krs.ms.gov.pl` / `api-krs`) wpisów, gdzie figuruje jako zarząd/wspólnik/fundator. Zwraca `Organization`/`Company` + `personOrganizationLinks`/`personCompanyLinks` z `basis=KRS`.
|
||||
2. Powiązania **organizacja↔organizacja** (`organizationLinks`) — wspólny KRS-owy adres, zarząd lub `nip` między dwiema organizacjami; `basis=KRS` lub `basis=NIP`.
|
||||
3. **`CeidgSource`** — kontrola krzyżowa jednoosobowych działalności gospodarczych osoby po CEIDG (`dane.biznes.gov.pl`, API publiczne) i po `nip`; `basis=CEIDG` lub `basis=NIP`.
|
||||
4. Deduplikacja: `Organization`/`Company` scalane po `krs` (klucz twardy, jednoznaczny) — w przeciwieństwie do `Person`, gdzie deduplikacja jest fuzzy i ostrożna (4.3 pkt 4), bo KRS/NIP są identyfikatorami unikalnymi z rejestru państwowego.
|
||||
5. Brak dopasowania po KRS/CEIDG/NIP dla danej osoby = brak wpisu (nie każda osoba w radzie ma powiązania biznesowe) — nie jest to luka do raportowania.
|
||||
|
||||
### 4.3. Normalizacja do formatu uwspólnionego
|
||||
1. **Nazwiska** (`NameNormalizer`): usunięcie tytułów do `titles[]`, `displayName` zachowuje oryginał, `fullName` = imię+nazwisko, `id` = slug z NFKD bez diakrytyków, lower-case, `-`. Uwaga na warianty (np. `Wojciech Łuczaj` występuje w kilku szpitalach).
|
||||
2. **Partie/komitety** (`PartyNormalizer`): mapowanie na kanoniczne nazwy (`Koalicja Obywatelska`, `PiS`, `PSL`, `Polska 2050`, `Trzecia Droga`, ...) + typ `PARTIA`/`KOMITET_WYBORCZY`/`KWW_LOKALNY`. `confidence` z markerów źródła (`NIEZWERYFIKOWANE` → `NIEZWERYFIKOWANA`, `brak danych` → `BRAK_DANYCH`, `brak/niepotwierdzona` → `NIEPOTWIERDZONA`).
|
||||
@@ -285,10 +366,12 @@ Odczytać plik(i) kanoniczne i zmaterializować graf w Neo4j: węzły, relacje i
|
||||
### 5.2. Model grafu
|
||||
**Węzły (labels):**
|
||||
- `:Hospital {id, name, shortName, city, voivodeship, legalForm, foundingBody, supervisoryBodyType, nip, krs, website, sourceUrls}`
|
||||
- `:Person {id, fullName, displayName, titles, sourceUrls}`
|
||||
- `:Person {id, fullName, displayName, titles, title, pwzNumber, sourceUrls}`
|
||||
- `:Party {name, type}` (partia/komitet)
|
||||
- `:GovBody {name, type, voivodeship, term}` (sejmik, rada powiatu, urząd gminy — dla mandatów)
|
||||
- `:Voivodeship {slug, name}` (grupowanie i zapytania regionalne)
|
||||
- `:Organization {id, name, krs, nip, sourceUrls}` (fundacje, stowarzyszenia)
|
||||
- `:Company {id, name, krs, nip, ceidgId, sourceUrls}` (spółki, działalności gospodarcze)
|
||||
|
||||
**Relacje:**
|
||||
| Relacja | Od → Do | Właściwości |
|
||||
@@ -300,6 +383,9 @@ Odczytać plik(i) kanoniczne i zmaterializować graf w Neo4j: węzły, relacje i
|
||||
| `[:CZLONEK_PARTII]` | Person → Party | `confidence, note, sourceUrls` |
|
||||
| `[:PELNI_MANDAT]` | Person → GovBody | `mandateType, term, sourceUrls` |
|
||||
| `[:W_WOJEWODZTWIE]` | Hospital → Voivodeship | — |
|
||||
| `[:CZLONEK_ORGANIZACJI]` | Person → Organization | `roleLabel, basis (KRS), sourceUrls` |
|
||||
| `[:POWIAZANA_Z]` | Organization → Organization | `basis (KRS/NIP), note, sourceUrls` |
|
||||
| `[:POWIAZANY_Z_FIRMA]` | Person → Company | `roleLabel, basis (KRS/CEIDG/NIP), sourceUrls` |
|
||||
|
||||
> Uwaga: zamiast osobnych typów relacji dla każdej funkcji można użyć jednej `[:PELNI_FUNKCJE {roleType, organ, ...}]`. Wybór: **typowane relacje** dla czytelności zapytań Cypher + `roleType` jako property dla filtrowania.
|
||||
|
||||
@@ -309,7 +395,10 @@ CREATE CONSTRAINT hospital_id IF NOT EXISTS FOR (h:Hospital) REQUIRE h.id IS UNI
|
||||
CREATE CONSTRAINT person_id IF NOT EXISTS FOR (p:Person) REQUIRE p.id IS UNIQUE;
|
||||
CREATE CONSTRAINT party_name IF NOT EXISTS FOR (x:Party) REQUIRE x.name IS UNIQUE;
|
||||
CREATE CONSTRAINT voiv_slug IF NOT EXISTS FOR (v:Voivodeship) REQUIRE v.slug IS UNIQUE;
|
||||
CREATE CONSTRAINT org_id IF NOT EXISTS FOR (o:Organization) REQUIRE o.id IS UNIQUE;
|
||||
CREATE CONSTRAINT company_id IF NOT EXISTS FOR (c:Company) REQUIRE c.id IS UNIQUE;
|
||||
CREATE INDEX person_name IF NOT EXISTS FOR (p:Person) ON (p.fullName);
|
||||
CREATE INDEX person_pwz IF NOT EXISTS FOR (p:Person) ON (p.pwzNumber);
|
||||
```
|
||||
|
||||
### 5.4. Ładowanie (parametryzowane, wsadowe)
|
||||
@@ -325,7 +414,30 @@ MERGE (hosp)-[:W_WOJEWODZTWIE]->(v);
|
||||
UNWIND $people AS p
|
||||
MERGE (person:Person {id: p.id})
|
||||
SET person += {fullName:p.fullName, displayName:p.displayName,
|
||||
titles:p.titles, sourceUrls:p.sourceUrls};
|
||||
titles:p.titles, title:p.title, pwzNumber:p.pwzNumber, sourceUrls:p.sourceUrls};
|
||||
|
||||
UNWIND $organizations AS o
|
||||
MERGE (org:Organization {id: o.id})
|
||||
SET org += {name:o.name, krs:o.krs, nip:o.nip, sourceUrls:o.sourceUrls};
|
||||
|
||||
UNWIND $companies AS c
|
||||
MERGE (comp:Company {id: c.id})
|
||||
SET comp += {name:c.name, krs:c.krs, nip:c.nip, ceidgId:c.ceidgId, sourceUrls:c.sourceUrls};
|
||||
|
||||
UNWIND $personOrganizationLinks AS pol
|
||||
MATCH (p:Person {id:pol.personId}), (org:Organization {id:pol.organizationId})
|
||||
MERGE (p)-[m:CZLONEK_ORGANIZACJI]->(org)
|
||||
SET m += {roleLabel:pol.roleLabel, basis:pol.basis, sourceUrls:pol.sourceUrls};
|
||||
|
||||
UNWIND $organizationLinks AS ol
|
||||
MATCH (a:Organization {id:ol.fromOrganizationId}), (b:Organization {id:ol.toOrganizationId})
|
||||
MERGE (a)-[m:POWIAZANA_Z]->(b)
|
||||
SET m += {basis:ol.basis, note:ol.note, sourceUrls:ol.sourceUrls};
|
||||
|
||||
UNWIND $personCompanyLinks AS pcl
|
||||
MATCH (p:Person {id:pcl.personId}), (comp:Company {id:pcl.companyId})
|
||||
MERGE (p)-[m:POWIAZANY_Z_FIRMA]->(comp)
|
||||
SET m += {roleLabel:pcl.roleLabel, basis:pcl.basis, sourceUrls:pcl.sourceUrls};
|
||||
|
||||
UNWIND $roles AS r
|
||||
MATCH (h:Hospital {id:r.hospitalId}), (p:Person {id:r.personId})
|
||||
@@ -393,8 +505,15 @@ RETURN p.fullName, collect(DISTINCT h.name) AS szpitale, collect(DISTINCT g.name
|
||||
MATCH (h:Hospital)-[:CZLONEK_ORGANU]->(p:Person)
|
||||
WITH p, collect(DISTINCT h) AS hs WHERE size(hs) > 1
|
||||
RETURN p.fullName, [x IN hs | x.name] AS szpitale;
|
||||
|
||||
// Osoby w organie szpitala mające jednocześnie powiązanie biznesowe (konflikt interesów)
|
||||
MATCH (h:Hospital)-[:CZLONEK_ORGANU]->(p:Person)
|
||||
WHERE (p)-[:POWIAZANY_Z_FIRMA]->() OR (p)-[:CZLONEK_ORGANIZACJI]->()
|
||||
OPTIONAL MATCH (p)-[:POWIAZANY_Z_FIRMA]->(comp:Company)
|
||||
OPTIONAL MATCH (p)-[:CZLONEK_ORGANIZACJI]->(org:Organization)
|
||||
RETURN p.fullName, h.name, collect(DISTINCT comp.name) AS firmy, collect(DISTINCT org.name) AS organizacje;
|
||||
```
|
||||
Eksport `overlap_report.csv` (osoba, szpitale, funkcje, partia, mandaty, `confidence`, `sourceUrls`).
|
||||
Eksport `overlap_report.csv` (osoba, szpitale, funkcje, partia, mandaty, firmy/organizacje, `confidence`, `sourceUrls`).
|
||||
|
||||
---
|
||||
|
||||
@@ -421,6 +540,9 @@ Model kanoniczny, schemat grafu i komendy pozostają niezmienne — nowe wojewó
|
||||
| Dane dynamiczne (zmiany kadr) | `validFrom`/`validTo` + `status` na relacji funkcji (`AKTUALNY`/`PELNIACY_OBOWIAZKI`/`ELEKT`/`BYLY`) |
|
||||
| Rate-limit / blokada scrapera | Exponential backoff; przełączenie na materiał `.md` jako cache; adnotacja źródła |
|
||||
| Spółka z o.o. (rada nadzorcza) vs SPZOZ (rada społeczna) | `supervisoryBodyType` + `organ` na relacji rozróżniają organy |
|
||||
| Wieloznaczne trafienie w rejestr.nil.org.pl (popularne nazwisko) | `pwzNumber=null`, `note="wieloznaczne trafienie NIL, wymaga ręcznej weryfikacji"`, wpis w `ingest-report.json` |
|
||||
| Brak trafienia w KRS/CEIDG dla osoby | Brak wpisu w `personOrganizationLinks`/`personCompanyLinks` — to nie luka (nie każdy ma powiązania biznesowe) |
|
||||
| Ta sama nazwa organizacji, różny KRS | Osobne węzły `:Organization` (dedup po `krs`, nie po nazwie) |
|
||||
|
||||
---
|
||||
|
||||
@@ -452,9 +574,10 @@ java -jar target/szpitale-graph.jar load --voivodeship podlaskie
|
||||
1. **Aplikacja Java 21 / Maven / Spring Shell** z komendami `ingest` (warstwa 1) i `load` (warstwa 2).
|
||||
2. **Model kanoniczny** (`canonical/*.json`) — wersjonowalny, wielowojewódzki snapshot danych.
|
||||
3. **Schemat Neo4j** — udokumentowane labels, typy relacji i właściwości (sekcja 5.2–5.3).
|
||||
4. **`overlap_report.csv`** — osoby łączące funkcje w organach szpitali z mandatami/partiami, z `sourceUrls` i `confidence`.
|
||||
5. **`ingest-report.json`** — statystyki i rejestr luk/rozbieżności per województwo.
|
||||
4. **`overlap_report.csv`** — osoby łączące funkcje w organach szpitali z mandatami/partiami/firmami/organizacjami, z `sourceUrls` i `confidence`.
|
||||
5. **`ingest-report.json`** — statystyki i rejestr luk/rozbieżności per województwo (w tym wieloznaczne trafienia PWZ).
|
||||
6. **Testy** — JUnit + Testcontainers (Neo4j) dla warstwy ładowania; testy jednostkowe normalizacji/deduplikacji.
|
||||
7. **Encje `Organization`/`Company`** w modelu kanonicznym i grafie, z powiązaniami do osób po KRS/CEIDG/NIP (sekcja 4.8, 5.2).
|
||||
|
||||
---
|
||||
|
||||
@@ -471,12 +594,15 @@ java -jar target/szpitale-graph.jar load --voivodeship podlaskie
|
||||
- [ ] Testy: parsowanie MD, normalizacja nazwisk, ładowanie do Testcontainers-Neo4j, zapytania walidacyjne.
|
||||
- [ ] Weryfikacja end-to-end na podlaskim, następnie dołożenie kolejnego województwa: `deep-research` → `research-<voiv>.md` → `ingest` → `load`.
|
||||
- [ ] Dla każdego nowego województwa: uruchomić skill `deep-research` (sekcja 4.6), zweryfikować oznaczenia `NIEZWERYFIKOWANA` przed użyciem, zapisać `research-<voiv>.md`.
|
||||
- [ ] `Person` rozszerzony o `title`/`pwzNumber` (sekcja 2, 4.7) + `PwzRegistrySource`.
|
||||
- [ ] Nowe rekordy modelu: `Organization`, `Company`, `PersonOrganizationLink`, `OrganizationLink`, `PersonCompanyLink` (sekcja 2) + `KrsSource`/`CeidgSource` (sekcja 4.8).
|
||||
- [ ] Warstwa 2: węzły `:Organization`/`:Company` + relacje `CZLONEK_ORGANIZACJI`/`POWIAZANA_Z`/`POWIAZANY_Z_FIRMA` (sekcja 5.2, 5.4) + constrainty (5.3).
|
||||
|
||||
---
|
||||
|
||||
## 11. Kolejka zadań dla lokalnego agenta (TDD, kroki atomowe)
|
||||
|
||||
Ta sekcja jest pisana pod **mały lokalny model** o ograniczonym kontekście. Każde zadanie jest samowystarczalne: jeden plik lub jedna metoda, dokładna ścieżka, dokładny test, jedna komenda weryfikacji, twarde kryterium ukończenia. Agent **nie planuje** — bierze pierwsze niezrobione zadanie i wykonuje je w całości.
|
||||
Ta sekcja jest pisana pod lokalny model wykonawczy **Qwen-3.6-35B-A3B** (MoE, ~3B aktywnych parametrów na token, mały efektywny kontekst, skłonność do zmyślania nieistniejących API przy niedoprecyzowanym zadaniu). Każde zadanie jest samowystarczalne: jeden plik lub jedna metoda, dokładna ścieżka, dokładny test, jedna komenda weryfikacji, twarde kryterium ukończenia. Agent **nie planuje** — bierze pierwsze niezrobione zadanie i wykonuje je w całości. Zasada 7 (poniżej) jest przy tym modelu szczególnie krytyczna: A3B chętnie "dopisuje" wygodne metody, których nie ma w `src/main/java` — zawsze czytaj plik przed wywołaniem metody.
|
||||
|
||||
### Reguły pracy (przeczytaj przed każdym zadaniem)
|
||||
|
||||
@@ -555,6 +681,47 @@ Ta sekcja jest pisana pod **mały lokalny model** o ograniczonym kontekście. Ka
|
||||
- Jeśli któreś [NEO4J] pominięte — odnotuj w tej checklistcie jako `[~]` z powodem.
|
||||
- DoD: `./mvnw -q verify` przechodzi (pomijając wyłącznie zadania bez Dockera).
|
||||
|
||||
**T9 — Rozszerzyć `Person` o `title` i `pwzNumber`**
|
||||
- Plik: `src/main/java/com/developx/szpitale/model/Person.java` (rekord z 5 polami: `id, fullName, displayName, titles, sourceUrls`).
|
||||
- Zamiar: dodać dwa nowe pola rekordu: `@JsonProperty("title") String title` (może być `null`) i `@JsonProperty("pwzNumber") String pwzNumber` (może być `null`), jako **ostatnie** dwa parametry konstruktora rekordu.
|
||||
- TDD:
|
||||
1. Test `PersonTest.person_withTitleAndPwzNumber_fieldsAccessible` w `src/test/java/com/developx/szpitale/model/PersonTest.java`: zbuduj `Person` z niepustym `title` i `pwzNumber`, asercja że `person.title()` i `person.pwzNumber()` zwracają wpisane wartości. RED (kompilacja nie przejdzie, bo konstruktor ma 5 argumentów) → dodaj pola → GREEN.
|
||||
2. Znajdź **wszystkie** miejsca konstruujące `new Person(...)` (`grep -rn "new Person(" src/`) i dopisz `null, null` (lub realną wartość jeśli już znana) na końcu wywołania — inaczej build nie skompiluje się.
|
||||
- DoD: `./mvnw -q compile` przechodzi; `./mvnw -q test -Dtest=PersonTest` zielony.
|
||||
|
||||
**T10 — `PwzRegistrySource` (fixture, bez żywego HTTP w teście)**
|
||||
- Nowy plik: `src/main/java/com/developx/szpitale/ingest/source/PwzRegistrySource.java`.
|
||||
- Zamiar (sekcja 4.7): metoda `Optional<String> lookupPwz(String fullName)` przyjmuje wynik zapytania do `rejestr.nil.org.pl` jako **wstrzykniętą zależność** (np. interfejs `PwzLookupClient` z metodą `List<String> query(String fullName)`), żeby test nie robił żywego HTTP.
|
||||
- Fixture: `src/test/resources/fixtures/nil-single-match.json` z jednym wynikiem (`["1234567"]`) i `nil-multiple-matches.json` z dwoma.
|
||||
- TDD:
|
||||
1. Test `PwzRegistrySourceTest.lookupPwz_singleMatch_returnsPwzNumber` → mock `PwzLookupClient` zwraca jeden wynik → `lookupPwz` zwraca `Optional.of("1234567")`.
|
||||
2. Test `PwzRegistrySourceTest.lookupPwz_multipleMatches_returnsEmpty` → mock zwraca 2 wyniki → `lookupPwz` zwraca `Optional.empty()` (wieloznaczność, patrz 4.7 pkt 2 — **nie zgadywać**, który wynik jest właściwy).
|
||||
3. Test `PwzRegistrySourceTest.lookupPwz_noMatch_returnsEmpty` → mock zwraca pustą listę → `Optional.empty()`.
|
||||
- DoD: `./mvnw -q test -Dtest=PwzRegistrySourceTest` zielony. Nie implementuj żywego klienta HTTP w tym zadaniu — tylko interfejs `PwzLookupClient` + logika `PwzRegistrySource` na nim.
|
||||
|
||||
**T11 — Rekordy `Organization`/`Company` + linki (round-trip)**
|
||||
- Nowe pliki: `src/main/java/com/developx/szpitale/model/Organization.java`, `Company.java`, `PersonOrganizationLink.java`, `OrganizationLink.java`, `PersonCompanyLink.java` — pola dokładnie jak w sekcji 2 PLAN.md (przykłady JSON), jako rekordy Java z `@JsonProperty` (wzoruj się na `Hospital.java`/`Person.java`).
|
||||
- Zamiar: `CanonicalDataset` (`src/main/java/com/developx/szpitale/model/CanonicalDataset.java`) dostaje 5 nowych pól-list: `organizations, companies, personOrganizationLinks, organizationLinks, personCompanyLinks` (domyślnie puste listy, nie `null`).
|
||||
- TDD:
|
||||
1. Test `OrganizationCompanyRoundTripTest.write_thenRead_preservesOrganizationsAndCompanies` w `src/test/java/com/developx/szpitale/ingest/` (mirror `CanonicalRoundTripTest` z T5): zbuduj `CanonicalDataset` z 1 `Organization`, 1 `Company`, po 1 linku każdego typu; zapisz `CanonicalWriter`, odczytaj `CanonicalReader`, porównaj pola. RED najpierw.
|
||||
2. Minimalny kod: dodaj rekordy + pola w `CanonicalDataset`, sprawdź że Jackson serializuje/deserializuje bez adnotacji dodatkowych (jak reszta modelu).
|
||||
- DoD: `./mvnw -q test -Dtest=OrganizationCompanyRoundTripTest` zielony.
|
||||
|
||||
**T12 — [NEO4J] `GraphLoader` ładuje `:Organization`/`:Company`**
|
||||
- Plik prod: `src/main/java/com/developx/szpitale/load/GraphLoader.java` (przeczytaj istniejącą metodę ładującą `Hospital`/`Person`, wzoruj się na jej strukturze).
|
||||
- Zamiar (sekcja 5.4): dodać metodę analogiczną do istniejącego ładowania węzłów, wykonującą `UNWIND $organizations ... MERGE (:Organization {id})`, `UNWIND $companies ... MERGE (:Company {id})` oraz 3 `MERGE` relacji: `CZLONEK_ORGANIZACJI`, `POWIAZANA_Z`, `POWIAZANY_Z_FIRMA` (dokładne zapytania Cypher w sekcji 5.4 PLAN.md).
|
||||
- Test integracyjny: `GraphLoaderOrganizationIT` z `@Testcontainers` (wzoruj się na istniejącym wzorcu z T6, jeśli `GraphLoaderIT` już istnieje — skopiuj setup kontenera).
|
||||
- `load_organizationAndCompany_nodesCreatedWithLinks` → załaduj 1 osobę + 1 organizację + 1 firmę + odpowiednie linki, sprawdź że istnieją węzły `:Organization`, `:Company` i relacje do `:Person`.
|
||||
- Wymaga Dockera. Bez Dockera → `[~]` + notatka (jak T6/T7).
|
||||
- DoD: `./mvnw -q test -Dtest=GraphLoaderOrganizationIT` zielony (lub pominięte z notatką).
|
||||
|
||||
**T13 — [NEO4J] `GraphValidator` — zapytanie o konflikt interesów**
|
||||
- Plik prod: `src/main/java/com/developx/szpitale/load/GraphValidator.java`.
|
||||
- Zamiar (sekcja 5.6): dodać metodę zwracającą wynik zapytania „osoby w organie szpitala z powiązaniem biznesowym" (dokładny Cypher w sekcji 5.6 PLAN.md, blok „konflikt interesów").
|
||||
- Test integracyjny `GraphValidatorOrganizationIT`: wgraj dataset z 1 osobą mającą `CZLONEK_ORGANU` (szpital) i `POWIAZANY_Z_FIRMA` (firma); asercja: wynik zawiera tę osobę z nazwą firmy.
|
||||
- Wymaga Dockera. Bez Dockera → `[~]` + notatka.
|
||||
- DoD: `./mvnw -q test -Dtest=GraphValidatorOrganizationIT` zielony (lub pominięte z notatką).
|
||||
|
||||
---
|
||||
|
||||
## 12. Sekcja postępu (aktualizuje lokalny agent)
|
||||
@@ -563,15 +730,27 @@ Po ukończeniu zadania agent zmienia jego status w liście poniżej i dopisuje j
|
||||
|
||||
- [x] T1 Deduplicator compile fix
|
||||
- [x] T2 NameNormalizer testy
|
||||
- [ ] T3 PartyNormalizer testy
|
||||
- [x] T3 PartyNormalizer testy
|
||||
- [x] T4 MarkdownRegistrySource test
|
||||
- [x] T5 Canonical round-trip
|
||||
- [~] T6 GraphLoader idempotencja [NEO4J] (skipped: Docker API too old)
|
||||
- [ ] T7 GraphValidator + CSV [NEO4J]
|
||||
- [ ] T8 Zielony pełny build
|
||||
- [~] T7 GraphValidator + CSV [NEO4J] (skipped: Docker API too old, jak T6)
|
||||
- [x] T8 Zielony pełny build
|
||||
- [x] T9 Person: title/pwzNumber
|
||||
- [ ] T10 PwzRegistrySource
|
||||
- [ ] T11 Organization/Company rekordy + round-trip
|
||||
- [ ] T12 GraphLoader: Organization/Company [NEO4J]
|
||||
- [ ] T13 GraphValidator: konflikt interesów [NEO4J]
|
||||
|
||||
**Dziennik (data — zadanie — wynik):**
|
||||
- (pusto)
|
||||
- 2026-07-07 — T1 — Deduplicator compile fix + unit tests [checkpoint] (commit 38a93d0)
|
||||
- 2026-07-07 — T2 — NameNormalizer testy + transliteratePolish, token-strip titles [checkpoint] (commit afe107c)
|
||||
- 2026-07-07 — T3 — PartyNormalizer testy + KO alias [checkpoint] (commit bc4eaac)
|
||||
- 2026-07-07 — T4 — MarkdownRegistrySource test + fix isPersonTable check [checkpoint] (commit 7f636a1)
|
||||
- 2026-07-07 — T5 — CanonicalWriter/Reader round-trip test [checkpoint] (commit b072cb3)
|
||||
- 2026-07-07 — T6/T8 — skip NEO4J tests (Docker API zbyt stary) + pełny build zielony [checkpoint] (commit 59d27b1)
|
||||
- 2026-07-08 — PLAN.md scalony z PLAN2.md (Person.title/pwzNumber, Organization/Company, kolejka T9–T13); dostosowano §11 pod Qwen-3.6-35B-A3B.
|
||||
- 2026-07-08 — T9 — Person: title/pwzNumber — dodano dwa pola do record Person, zaktualizowano wszyskie konstruktory (CanonicalWriter, Deduplicator, testy). 7 testow zielonych.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "Stan wykonania kolejki zadań lokalnego agenta (PLAN2.md §11-13). Zrodlo prawdy przy konflikcie: git log.",
|
||||
"resumeHint": "Wczytaj ten plik, znajdz pierwszy task o statusie todo/in_progress. Jesli in_progress i drzewo git brudne -> git checkout -- . && git clean -fd, ustaw task na todo, zacznij od zera (PLAN2.md §13.1).",
|
||||
"createdAt": "2026-07-07",
|
||||
"updatedAt": "2026-07-08",
|
||||
"updatedAt": "2026-07-08T23:03:00Z",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "T1",
|
||||
@@ -82,10 +82,10 @@
|
||||
"id": "T9",
|
||||
"title": "Person: title/pwzNumber",
|
||||
"tag": null,
|
||||
"status": "todo",
|
||||
"startedAt": null,
|
||||
"finishedAt": null,
|
||||
"note": "PLAN2.md delta: rozszerzenie Person o title i pwzNumber (PLAN.md sekcja 2, T9)."
|
||||
"status": "done",
|
||||
"startedAt": "2026-07-08T23:00:00Z",
|
||||
"finishedAt": "2026-07-08T23:03:00Z",
|
||||
"note": "Dodano title i pwzNumber do Person record. Zaktualizowano wszystkie nowicje Person (CanonicalWriter, Deduplicator, testy). 7 testow zielonych."
|
||||
},
|
||||
{
|
||||
"id": "T10",
|
||||
|
||||
@@ -73,7 +73,7 @@ public class CanonicalWriter {
|
||||
if (!peopleMap.containsKey(personId)) {
|
||||
peopleMap.put(personId, new Person(
|
||||
personId, extractedName, personEntry.displayTitle(),
|
||||
titles, new ArrayList<>()
|
||||
titles, new ArrayList<>(), null, null
|
||||
));
|
||||
personUrlsMap.put(personId, new LinkedHashSet<>());
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class CanonicalWriter {
|
||||
if (p != null) {
|
||||
updatedPeople.add(new Person(
|
||||
p.id(), p.fullName(), p.displayName(),
|
||||
p.titles(), new ArrayList<>(entry.getValue())
|
||||
p.titles(), new ArrayList<>(entry.getValue()), null, null
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -49,7 +49,8 @@ public class Deduplicator {
|
||||
first.fullName(),
|
||||
first.displayName(),
|
||||
first.titles(),
|
||||
new ArrayList<>(allUrls)
|
||||
new ArrayList<>(allUrls),
|
||||
null, null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ public record Person(
|
||||
@JsonProperty("fullName") String fullName,
|
||||
@JsonProperty("displayName") String displayName,
|
||||
@JsonProperty("titles") List<String> titles,
|
||||
@JsonProperty("sourceUrls") List<String> sourceUrls
|
||||
@JsonProperty("sourceUrls") List<String> sourceUrls,
|
||||
@JsonProperty("title") String title,
|
||||
@JsonProperty("pwzNumber") String pwzNumber
|
||||
) {
|
||||
}
|
||||
|
||||
+8
-4
@@ -24,14 +24,16 @@ class DeduplicatorTest {
|
||||
"Jan Kowalski",
|
||||
"Jan Kowalski",
|
||||
List.of(),
|
||||
List.of("https://example.com/1")
|
||||
List.of("https://example.com/1"),
|
||||
null, null
|
||||
);
|
||||
Person janKowaski = new Person(
|
||||
"person:jan-kowaski",
|
||||
"Jan Kowaski",
|
||||
"Jan Kowaski",
|
||||
List.of(),
|
||||
List.of("https://example.com/2")
|
||||
List.of("https://example.com/2"),
|
||||
null, null
|
||||
);
|
||||
|
||||
List<Person> input = List.of(janKowalski, janKowaski);
|
||||
@@ -50,14 +52,16 @@ class DeduplicatorTest {
|
||||
"Jan Kowalski",
|
||||
"Jan Kowalski",
|
||||
List.of(),
|
||||
List.of("https://example.com/1")
|
||||
List.of("https://example.com/1"),
|
||||
null, null
|
||||
);
|
||||
Person second = new Person(
|
||||
"person:jan-kowalski",
|
||||
"Jan Kowalski",
|
||||
"Jan Kowalski",
|
||||
List.of(),
|
||||
List.of("https://example.com/2")
|
||||
List.of("https://example.com/2"),
|
||||
null, null
|
||||
);
|
||||
|
||||
List<Person> result = deduplicator.deduplicate(List.of(first, second));
|
||||
|
||||
@@ -40,7 +40,8 @@ class CanonicalRoundTripTest {
|
||||
"Jan Kowalski",
|
||||
"Dyrektor Naczelny",
|
||||
List.of("prof."),
|
||||
List.of("https://uskwb.pl/dyrekcja")
|
||||
List.of("https://uskwb.pl/dyrekcja"),
|
||||
null, null
|
||||
);
|
||||
|
||||
Affiliation affiliation = new Affiliation(
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.developx.szpitale.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PersonTest {
|
||||
|
||||
@Test
|
||||
void person_withTitleAndPwzNumber_fieldsAccessible() {
|
||||
Person person = new Person(
|
||||
"person:jan-kochanowicz",
|
||||
"Jan Kochanowicz",
|
||||
"prof. dr hab. n. med. Jan Kochanowicz",
|
||||
List.of("prof.", "dr hab.", "n. med."),
|
||||
List.of("https://uskwb.pl/dyrekcja-szpitala/"),
|
||||
"prof. dr hab. n. med.",
|
||||
"1234567"
|
||||
);
|
||||
|
||||
assertEquals("prof. dr hab. n. med.", person.title());
|
||||
assertEquals("1234567", person.pwzNumber());
|
||||
}
|
||||
}
|
||||
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
com/developx/szpitale/ingest/normalize/NameNormalizerTest.class
|
||||
com/developx/szpitale/ingest/normalize/PartyNormalizerTest.class
|
||||
com/developx/szpitale/model/PersonTest.class
|
||||
com/developx/szpitale/ingest/source/MarkdownRegistrySourceTest.class
|
||||
com/developx/szpitale/ingest/normalize/DeduplicatorTest.class
|
||||
com/developx/szpitale/load/GraphLoaderIT.class
|
||||
com/developx/szpitale/load/CanonicalRoundTripTest.class
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@
|
||||
/home/kruszewskia/Workspace/Private/Szpitale-graph/szpitale-graph/src/test/java/com/developx/szpitale/ingest/normalize/PartyNormalizerTest.java
|
||||
/home/kruszewskia/Workspace/Private/Szpitale-graph/szpitale-graph/src/test/java/com/developx/szpitale/ingest/source/MarkdownRegistrySourceTest.java
|
||||
/home/kruszewskia/Workspace/Private/Szpitale-graph/szpitale-graph/src/test/java/com/developx/szpitale/load/CanonicalRoundTripTest.java
|
||||
/home/kruszewskia/Workspace/Private/Szpitale-graph/szpitale-graph/src/test/java/com/developx/szpitale/load/GraphLoaderIT.java
|
||||
/home/kruszewskia/Workspace/Private/Szpitale-graph/szpitale-graph/src/test/java/com/developx/szpitale/model/PersonTest.java
|
||||
|
||||
+5
-5
File diff suppressed because one or more lines are too long
+14
-14
File diff suppressed because one or more lines are too long
+8
-8
File diff suppressed because one or more lines are too long
+7
-7
File diff suppressed because one or more lines are too long
+4
-4
File diff suppressed because one or more lines are too long
+59
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,4 +1,4 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.developx.szpitale.ingest.normalize.DeduplicatorTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.006 s -- in com.developx.szpitale.ingest.normalize.DeduplicatorTest
|
||||
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.008 s -- in com.developx.szpitale.ingest.normalize.DeduplicatorTest
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.developx.szpitale.ingest.normalize.NameNormalizerTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 25, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.078 s -- in com.developx.szpitale.ingest.normalize.NameNormalizerTest
|
||||
Tests run: 25, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.081 s -- in com.developx.szpitale.ingest.normalize.NameNormalizerTest
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.developx.szpitale.ingest.normalize.PartyNormalizerTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 15, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.011 s -- in com.developx.szpitale.ingest.normalize.PartyNormalizerTest
|
||||
Tests run: 15, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.010 s -- in com.developx.szpitale.ingest.normalize.PartyNormalizerTest
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.developx.szpitale.ingest.source.MarkdownRegistrySourceTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.100 s -- in com.developx.szpitale.ingest.source.MarkdownRegistrySourceTest
|
||||
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.101 s -- in com.developx.szpitale.ingest.source.MarkdownRegistrySourceTest
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.developx.szpitale.load.CanonicalRoundTripTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.187 s -- in com.developx.szpitale.load.CanonicalRoundTripTest
|
||||
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.165 s -- in com.developx.szpitale.load.CanonicalRoundTripTest
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.developx.szpitale.model.PersonTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 s -- in com.developx.szpitale.model.PersonTest
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user