Files
2026-07-17 17:07:08 +02:00

6.8 KiB

API aplikacji kart

Wspólna aplikacja Fastify wystawia stan dowolnej karty, nawigację UML, checkpointy oraz Neovim wybrany przez MCP. Domyślny adres lokalnej instancji to http://127.0.0.1:8080. Kontrakt nie zależy od serii ani konkretnej karty; dane i recepty pochodzą z jej card_source.json.

API nie zarządza cyklem życia kontenera i nie podpina pane tmuxa. Za operacje start/reset/refresh/attach/detach odpowiada stemctl session. API korzysta z kontenera wskazanego przez bieżący wybór MCP i steruje zawartością jego sesji: Neovimem, Termdebugiem/GDB i checkpointami maszyny.

Tożsamość i stan

Metoda i endpoint Znaczenie
GET /api/identity id, UUID, wersja i SHA-256 źródłowego JSON-a karty.
GET /api/card-revision Rewizja plików używana do automatycznego odświeżania strony.
GET /api/state Złożony stan nawigacji, widoku, checkpointu i dostępności Neovima.
GET /api/control/state Lekki stan synchronizacji strony z klientem sterującym.

Serwer jest przeznaczony do pracy lokalnej. Nie ma warstwy uwierzytelnienia, dlatego nie należy wystawiać go bezpośrednio poza zaufany host.

Nawigacja UML

Hierarchia nawigacji jest stała:

card → task → block → phase → step → snapshot

Ruch kursora przez move lub PUT current nie uruchamia symulatora. Jawna aktywacja odbywa się przez Enter w WWW albo F2 w WWW/Neovimie, które wywołują POST /api/navigation/sync. Dla poziomu BLOCK backend wybiera pierwszy STEP tego bloku. CARD i TASK są odrzucane, ponieważ nie wskazują konkretnego checkpointu diagramu.

Metoda i endpoint Znaczenie
GET /api/keyboard Skróty i obsługiwane poziomy nawigacji.
GET /api/navigation/catalog Wszystkie prawidłowe pozycje i ich indeksy.
GET /api/navigation/current Bieżąca pozycja oraz status checkpointu.
PUT /api/navigation/current Ustawia dokładną pozycję i poziom fokusu.
POST /api/navigation/move Przesuwa kursor o delta na wybranym poziomie.
POST /api/navigation/sync Odtwarza checkpoint przypisany do bieżącej, zapisanej pozycji.

Przykład ustawienia kroku — identyfikatory są danymi konkretnej karty:

{
  "task_id": "<task-id>",
  "block_id": "<block-id>",
  "phase_id": "<phase-id>",
  "step_id": "<step-id>",
  "snapshot_ref": "<snapshot-ref>",
  "focus_level": "step",
  "sync_requested": true,
  "actor": "stemctl"
}

Checkpointy

Metoda i endpoint Znaczenie
GET /api/checkpoint/status Aktywna operacja, ostatni wynik i generacja.
POST /api/checkpoint/activate Odtwarza stan GDB przypisany do snapshotu.

Wywołanie orkiestratora przypina zarówno kontener, jak i rewizję karty:

{
  "snapshot_ref": "<snapshot-ref>",
  "generation": 1784280000000,
  "expected_binding": {
    "container_id": "<container-id>",
    "instance": "<instance-id>",
    "profile": "hazard3-sim",
    "target": "hazard3-baremetal"
  },
  "expected_identity": {
    "id": "<card-id>",
    "uuid": "<card-uuid>",
    "version": "<card-version>",
    "source_sha256": "<sha256>"
  }
}

Backend przechowuje bieżącą nawigację i stan viewera w SQLite. Domyślna baza to .stem/card-state.sqlite3; ścieżkę można zmienić przez CARD_STATE_DATABASE. Ta sama aplikacja wystawia HTTP również przez lokalny socket .stem/card-api.sock (CARD_API_SOCKET). Repozytorium jest montowane w kontenerze jako /workspace, dlatego Neovim wywołuje API przez /workspace/.stem/card-api.sock bez otwierania dodatkowego portu sieciowego.

Replay kończy się powodzeniem wyłącznie ze statusem ready. Zmiana kontenera, socketu MCP albo źródłowego JSON-a podczas operacji powoduje odrzucenie wyniku; pozycja strony i SYNC ON nie są wtedy publikowane.

Widok i Neovim

Metoda i endpoint Znaczenie
GET/PUT /api/viewer/state Skala, scroll oraz visible/sync/control/expanded/fit.
GET /api/nvim/state Bieżący bufor, okno, kursor i tryb Neovima.
PUT /api/nvim/cursor Ustawia row, column i opcjonalnie window.
POST /api/nvim/input Przekazuje do 256 znaków przez nvim_input.
POST /api/nvim/reset Resetuje cel i odświeża debugger (F1).
POST /api/nvim/redraw Dopasowuje host pane i grid UI, a następnie wykonuje pełny redraw (`Ctrl+``).
WS /api/nvim-ui Strumień zewnętrznego UI Neovima do panelu WWW.

Pole viewer.scroll zapisuje położenie dokumentu (x, y), numer strony page_index oraz sheet_scroll_top dla jej wewnętrznego obszaru. Dzięki temu sterowanie API odtwarza ten sam fragment diagramu także wtedy, gdy przy dużym powiększeniu przewija się najpierw zawartość strony, a dopiero potem dokument.

Wyłączenie viewer.nvim.sync automatycznie wyłącza również viewer.nvim.control. Samo ponowne włączenie synchronizacji nie uzbraja sterowania klawiaturą bez jawnego control: true.

viewer.allocator.visible przechowuje stan przypiętego modelu alokatora. Model jest przełączany przez Alt+6 i pokazuje fazę/krok, allocp, zajętość areny oraz wartości związane z bieżącym checkpointem.

Podział odpowiedzialności widoków

Interaktywny diagram UML pokazuje przepływ i służy do wyboru kroku. Nie renderuje pod SVG osobnych paneli kodu, terminala, rejestrów, pamięci ani ramki stosu. Te dane prezentuje Nvim view, ustawiany przez snapshot wybranego kroku. Snapshoty pozostają w JSON/API, mimo że nie są powielane wizualnie pod diagramem.

Postęp zajęć i raport

Metoda i endpoint Znaczenie
GET /api/progress Katalog, statusy i podsumowanie wykonania.
PUT /api/progress/:itemId Ustawia pending albo approved, notatkę i aktora.
GET /api/report/teams.md Generuje bieżący raport Markdown do Teams.
GET/POST /api/events Odczytuje lub dopisuje chronologiczne zdarzenia z timestampem backendu.
POST /api/evidence Zapisuje PNG/JPEG i przypina go do zdarzenia.
GET /api/evidence/:name Udostępnia zapisany dowód.
GET /api/report/lesson.html Renderuje chronologiczny raport HTML z dowodami.

Zdarzenia są dopisywane do SQLite i obejmują nawigację, aktywacje checkpointów, reset/redraw Neovima, zmiany viewera oraz postęp. Dzięki temu raport pokazuje rzeczywistą kolejność pracy, a nie wyłącznie końcowy stan.

Planowane strategie i adnotacje

Strategie debugowania będą przypinane do pełnego klucza task/block/phase/step/snapshot. Adnotacja pozostanie osobnym rekordem:

strategy: id, label, commands, expected_observations
annotation: id, strategy_id, target, geometry, style, text, visible

Planowane operacje show/hide/toggle zmienią wyłącznie visible. add/remove będą osobnymi, audytowalnymi operacjami. Dzięki temu ukrycie warstwy objaśnień nie usuwa przygotowanych oznaczeń.