Decyzje: jak działają (D0–D4)¶
Owner answers recorded from chat¶
When the owner explicitly answers in chat, an interactive session can call
decision_record_owner_answer to record that answer on the decision board.
owner_chat is an attestation by the recording session, not cryptographic proof.
Nothing is recorded automatically. The historical passkey-only description below
predates this addition; /decide and delegations keep their existing rules.
The caller needs a current owner/admin project role, tasks:write, matching
write_context and an idempotency key. OAuth and project tokens are supported.
Execution credentials return decision_record_requires_interactive_session before
the scope gate; contributor/viewer roles return project_admin_required before it.
Legacy OAuth without a grant-family principal returns principal_unavailable.
New mode takes the proposal fields for consent or rule, plus option_id,
verbatim owner_quote (1–1000 characters), session_label (1–80) and said_at
(ISO-8601 with timezone, at most seven days old, never future). Existing mode
takes decision_id of a proposed decision and the answer fields; its immutable
content hash is used without a duplicate. Proposal fields in this mode do not
replace the stored content. A new record with a pending same-key proposal returns
decision_record_pending_exists with its ID for use in existing mode.
Payments, secrets and deletion require the owner's key. All options' consequences
must be free of these operations; the session attests to that by explicitly setting
owner_list.paid, secret and deletion to false. True flags, including a generic
key with paid=true, and cost-, secret-, delete- prefixes return
decision_requires_owner_key. Migration is allowed. Staffing is refused with
decision_record_type_not_allowed, and approval values with
decision_record_approval_not_allowed; approval routes remain key-only.
Past conditions.valid_until returns decision_record_expired in new mode.
Refusals write no decision or answer event.
The transaction records confirmed for authorizes=true, otherwise rejected,
without decision_waiting or push delivery rows. said_at is the owner's answer
time; created_at remains the recording time. List/get and the continuity in-force
index expose confirmed_by: owner_chat, attested_by: {principal, session_label}
and answered_in: {quote, session_label, said_at}. The principal is server-derived.
Consent can be consumed once with decision_check(use=true) unless retry is allowed;
rules use false (decision_use_not_applicable otherwise). Existing key revocation
still applies.
Reuse the same idempotency key only for an identical retry. Replay precedes the
seven-day age check, and concurrent identical calls return one record. Different
input or another principal with the same key returns idempotency_conflict.
Historical D0–D4 description¶
Stan odczytany ponownie 2026-10-10 z h8v6/heyaira@b1a29d484f60414125101279f38866ab48e5c16e
(zadanie v24; kod bez zmian względem poprzedniego opisu).
Opis dotyczy kodu tej rewizji; D0 jest punktem porównania. docs.heyaira.eu powstaje
z docs/ (mkdocs.yml:6, docs/operations/documentation-workflow.md:30). Odczyt
witryny jest zablokowany przez listę dozwolonych domen wykonania; „publiczne docs” oznaczają ich
źródła w repozytorium, nie potwierdzony stan publikacji.
Opis przejścia przez passkey wynika z kodu i testów syntetycznych; to wykonanie
nie sprawdzało Touch ID, Face ID ani dostarczenia push na prawdziwym urządzeniu.
Czym jest decyzja i kto ją proponuje¶
| Element | Działanie w kodzie | Źródło |
|---|---|---|
| Decyzja | Niezmienna propozycja w decisions i dopisywana historia w decision_events. Stan jest wyliczany przy odczycie. Stara notatka memory kind=decision nie uzyskuje przez to in_force. |
migrations/054_decisions.sql:2, migrations/054_decisions.sql:43, migrations/054_decisions.sql:74, src/heyaira/decisions.py:71, src/heyaira/server.py:3808 |
| Typ | consent: zgoda na czynność; rule: reguła; staffing: delegacja odpowiedzi przypisana do rodziny połączenia OAuth. |
src/heyaira/decisions.py:280, src/heyaira/decisions.py:335, src/heyaira/decision_answers.py:190 |
| Proponujący | Sesja z tasks:write i principalem ustalonym przez serwer, np. koordynator lub agent w sesji interaktywnej. Agent wysłany przez Bridge z tokenem wykonania nie może proponować ani odpowiadać; może odczytać decyzje swojego zadania. |
src/heyaira/decisions.py:389, src/heyaira/decisions.py:173, src/heyaira/server.py:3638 |
| Treść propozycji | Pytanie zakończone ?, 2–6 opcji, konsekwencje każdej (co się stanie, co blokuje, odwracalność), rekomendacja z uzasadnieniem, kto czeka, zakres, klucz, cztery flagi właściciela oraz cytat i miejsce źródła. Serwer odrzuca niekompletne dane. Cytat nie jest zgodą. |
src/heyaira/decisions.py:233, src/heyaira/decisions.py:282, src/heyaira/server.py:3624, src/heyaira/decision_answers.py:174 |
| Zakres | Projekt, moduł albo zadanie z konkretną wersją. Moduł to slug; przynależność zadania wynika z tagu modul-<slug>. Dla jednego klucza wygrywa obowiązująca decyzja o najwęższym zakresie: zadanie → moduł → projekt. |
src/heyaira/decisions.py:64, src/heyaira/decisions.py:128, src/heyaira/decisions.py:289 |
| Odpowiedź właściciela | Każda akcja wymaga jego klucza potwierdzającego: wybór opcji, odmowa, dopytanie, odwołanie. Token projektu, nazwa sesji i tekst „tak” nie zastępują assertion passkey. | src/heyaira/decision_passkeys.py:147, src/heyaira/decision_passkeys.py:162, src/heyaira/decision_answers.py:108 |
| Delegat | Może zatwierdzić lub odmówić w granicach obowiązującego staffing: właściwy principal OAuth, prefiks klucza, typ i zakres. Nie odpowiada na własną propozycję; nie rozstrzyga staffing, migracji, usuwania, kosztów ani sekretów; nie dopytuje i nie odwołuje. |
src/heyaira/decision_answers.py:190, src/heyaira/decisions.py:303, src/heyaira/decisions.py:353 |
Co właściciel widzi w każdym kanale¶
| Kanał | Lista i wybór | Gdzie następuje odpowiedź | Źródło |
|---|---|---|---|
Claude Code: mod /heyaira-decisions |
Belka nad promptem z liczbą decyzji i blokujących; jedna decyzja otwiera stronę, kilka otwiera panel. Panel pokazuje pytanie, pełne konsekwencje, rekomendację, czekającą sesję, zakres i konflikty; stale/lapsed trafiają do „Do uzupełnienia”. Odczyt dotyczy jednego projektu wybranego po nazwie folderu w ścieżce. Odświeżanie: start, co 5 minut i przycisk, najwyżej raz na 60 s. |
Przycisk opcji pobiera świeży link i otwiera przeglądarkę z ?option=<id>; „Dopytaj” z ?ask=1. Na stronie trzeba jeszcze nacisnąć potwierdzenie i użyć passkey. Mod wykonuje wyłącznie odczyty. |
clients/claude-mod/hooks/register.tsx:15, clients/claude-mod/hooks/register.tsx:25, clients/claude-mod/hooks/register.tsx:138, clients/claude-mod/hooks/register.tsx:281, clients/claude-mod/hooks/register.tsx:328, clients/claude-mod/hooks/register.tsx:424, clients/claude-mod/hooks/format.ts:46, clients/claude-mod/hooks/format.ts:124 |
Codex: plugin heyaira-decisions |
Skill uruchamiany prośbą „pokaż decyzje” / heyaira-decisions; model ma wypisać polską listę z kanonicznego formatu i przejść wszystkie kursory. W repozytorium projekt wybiera z Git origin i project_repositories; folder stosuje tylko poza Git. To instrukcja dla modelu, bez własnej belki/panelu i timera. |
Wypisany Rozstrzygnij: <confirm_url> jest linkiem do przeglądarki. Prośba o potwierdzenie w czacie dostaje link, nie zapis odpowiedzi. W sesji wykonawczej link jest niedostępny: sprawę przekazuje się koordynatorowi w RESULT. |
clients/codex-plugin/.codex-plugin/plugin.json:8, clients/codex-plugin/skills/heyaira-decisions/SKILL.md:11, clients/codex-plugin/skills/heyaira-decisions/SKILL.md:34, clients/codex-plugin/skills/heyaira-decisions/SKILL.md:64, clients/codex-plugin/skills/heyaira-decisions/SKILL.md:105 |
Strona /decide/<handle> |
Pytanie i nazwa projektu, kto czeka, główny przycisk rekomendacji, inne opcje, konsekwencje. Konflikt blokuje zatwierdzenie; lista poprzedników pokazuje, co zostanie zastąpione. „Details” zawiera stan, zakres z wersją, principal i klienta autora, warunki, przesłonięcie, źródło i interpretowany grant staffing. ?option= pokazuje wybraną opcję; ?ask=1 formularz pytania. |
Strona pobiera challenge i uruchamia navigator.credentials.get; zapis odpowiedzi jest osobnym POST. proposed: wybór/odmowa/dopytanie; stale: tylko odmowa; in_force: odwołanie; lapsed i stany zamknięte: brak odpowiedzi. Ogólny „Reject” jest wyświetlany tylko wtedy, gdy nie ma dostępnej opcji odmowy. |
src/heyaira/decision_web.py:149, src/heyaira/decision_web.py:170, src/heyaira/decision_web.py:209, src/heyaira/decision_web.py:241, src/heyaira/decision_web.py:264, src/heyaira/decision_web.py:273, src/heyaira/decision_web.py:79, src/heyaira/decision_answers.py:108 |
| iPhone | Na górze Inbox są „Decisions” i „Needs input”. Ekran decyzji pokazuje pytanie, kto czeka, pierwsze zdanie uzasadnienia, opcje (rekomendowana pierwsza), konsekwencje i „Ask back”. stale/lapsed nie mają przycisków odpowiedzi. Push otwiera decyzję z listy open; gdy jej tam nie ma, aplikacja wraca do wpisu powiadomienia. |
Aplikacja pobiera link i otwiera /decide w ASWebAuthenticationSession z ?option= lub ?ask=1 oraz return=ios. Passkey działa na stronie w systemowym oknie; callback wraca do aplikacji, która odświeża listę. Nie ma natywnej ceremonii WebAuthn. Obecny skrypt zapisuje kanał web, również z telefonu. |
ios/HeyAiraBridge/HeyAiraBridge/DecisionViews.swift:8, ios/HeyAiraBridge/HeyAiraBridge/DecisionViews.swift:127, ios/HeyAiraBridge/HeyAiraBridge/DecisionViews.swift:154, ios/HeyAiraBridge/HeyAiraBridge/DecisionStore.swift:65, ios/HeyAiraBridge/HeyAiraBridge/DecisionStore.swift:112, ios/HeyAiraBridge/HeyAiraBridge/DecisionAuthSession.swift:13, ios/HeyAiraBridge/HeyAiraBridge/DecisionModels.swift:245, ios/HeyAiraBridge/HeyAiraBridge/AppModel.swift:168, src/heyaira/decision_web.py:85, src/heyaira/decision_passkeys.py:167 |
Lista REST na telefonie wymaga tasks:read oraz aktywnego urządzenia dla subjectu
zalogowanej sesji; obejmuje projekt tokenu. Lista Maca wymaga tożsamości Bridge
i powiązania z projektem. Samo zarejestrowanie telefonu nie nadaje uprawnienia do
odpowiedzi właściciela (src/heyaira/decision_web.py:390,
src/heyaira/decision_passkeys.py:162).
Mod Claude i iPhone pobierają najwyżej 10 stron po 50 pozycji. Mod zgłasza niepełną
listę, iPhone nie pokazuje ostrzeżenia o dalszym kursorze. Belka Claude liczy tylko
decyzje poza stale/lapsed; same uzupełnienia są dostępne przez komendę panelu,
bez belki (clients/claude-mod/hooks/register.tsx:98,
clients/claude-mod/hooks/register.tsx:159, clients/claude-mod/hooks/register.tsx:340,
clients/claude-mod/hooks/format.ts:95, ios/HeyAiraBridge/HeyAiraBridge/DecisionStore.swift:84).
Sam odczyt decision_check(use=false) wymaga tasks:read; zużycie zgody (use=true)
wymaga dodatkowo tasks:write, write_context i klucza idempotencji
(src/heyaira/server.py:3678, src/heyaira/server.py:3681, src/heyaira/decisions.py:389).
Co potwierdza passkey¶
| Krok | Powiązanie i sprawdzenie | Źródło |
|---|---|---|
| Klucz | Klucz należy do osoby na poziomie konta. Pierwszy wymaga jednorazowego kodu (do 15 min), wysyłanego e-mailem przez CLI DevOps; błąd wysyłki wycofuje wydanie kodu. Kolejne wymagają aktywnego klucza tej osoby. Lista i odwołanie kluczy też wymagają assertion. | migrations/055_decision_passkeys.sql:2, migrations/055_decision_passkeys.sql:16, src/heyaira/admin.py:768, src/heyaira/decision_passkeys.py:178, src/heyaira/decision_passkeys.py:229, src/heyaira/decision_passkeys.py:254 |
| Link | Podpis HMAC wiąże projekt, ID decyzji, content_hash, identyfikator klucza serwera i ważność 24 h. Link pozwala zobaczyć tę decyzję, nie odpowiedzieć. Treść strony pochodzi z bazy. Utworzenie linku nie zapisuje rekordu. |
src/heyaira/decision_answers.py:49, src/heyaira/decision_answers.py:79, src/heyaira/decision_web.py:156 |
| Challenge | Ważny 2 min, maksymalnie pięć niewygasłych na decyzję. Wiąże ID i hash treści, akcję, konkretną opcję, hash notatki i — przy zatwierdzeniu staffing — hash grantu. |
src/heyaira/decision_passkeys.py:25, src/heyaira/decision_passkeys.py:72, src/heyaira/decision_answers.py:160 |
| Assertion | Serwer sprawdza podpis, RP heyaira.eu, dokładny origin serwera, weryfikację użytkownika i licznik; klucz musi być aktywny i należeć do obecnego accounts.owner_subject_id. Touch ID / Face ID to sposób obsługi urządzenia; serwer wymaga UV, nie konkretnej biometrii. |
src/heyaira/decision_passkeys.py:18, src/heyaira/decision_passkeys.py:99, src/heyaira/decision_passkeys.py:162 |
| Zapis | W transakcji serwer ponownie sprawdza stan, konflikt, grant i zgodność challenge; dopisuje zdarzenie, zużywa challenge oraz zapisuje audyt i powiadomienie. Ponowne użycie challenge jest odrzucane. Parametry ?option= / return=ios nie są zgodą. |
src/heyaira/decision_passkeys.py:125, src/heyaira/decision_passkeys.py:147, src/heyaira/decision_web.py:149 |
Od propozycji do obowiązywania i wznowienia zadania¶
| Sytuacja | Skutek | Źródło |
|---|---|---|
| Propozycja bez odpowiedzi | proposed; zmiana wersji zadania lub dopytanie daje stale. Upływ ważności albo zamknięcie zadania zakresu przed odpowiedzią daje lapsed. |
src/heyaira/decisions.py:71 |
| Wybrana opcja ze zgodą | Zdarzenie confirmed; decyzja jest in_force, jeśli nie została zastąpiona, odwołana ani nie wygasła. Opcja authorizes=false lub ogólna odmowa zapisuje rejected, nigdy zgodę. |
src/heyaira/decision_answers.py:174, src/heyaira/decisions.py:71, migrations/054_decisions.sql:120 |
| Zmiana lub wycofanie | Autor może wycofać otwartą propozycję (withdrawn) albo zgłosić nową z revises_id; wcześniejsza dostaje zdarzenie wycofania. Właściciel może odwołać obowiązującą (revoked). Potwierdzony następca zastępuje całe drzewo supersedes (superseded); jego późniejsze wygaśnięcie nie przywraca poprzedników. |
src/heyaira/decisions.py:52, src/heyaira/decisions.py:74, src/heyaira/decisions.py:457, src/heyaira/decisions.py:511, src/heyaira/decision_answers.py:113 |
| Użycie zgody | decision_check sprawdza stan, zakres, pierwszeństwo, konflikt, bieżącą wersję zadania i wybraną opcję. use=true dotyczy tylko consent i dopisuje used; jednorazowa zgoda staje się expired. retry_allowed=true pozwala na kolejne użycia. Zgody modułu/projektu domyślnie wygasają po 30 dniach; valid_until może skrócić ważność. Tekst stop_if/rollback nie jest wykonywany przez serwer. |
src/heyaira/decisions.py:140, src/heyaira/decisions.py:84, src/heyaira/decisions.py:308, src/heyaira/decisions.py:324, src/heyaira/decisions.py:472 |
Propozycja z waiting.blocks_task_id |
Automatyczny hold w tej samej transakcji. Koordynator może też dodać hold do decyzji bez wskazanego zadania, jeżeli jej zakres je obejmuje. Zamknięte zadania nie przyjmują nowych holdów. Hold nie zmienia wersji, zapisanego etapu ani workflow. | src/heyaira/decisions.py:491, src/heyaira/decisions.py:533, src/heyaira/decisions.py:539, src/heyaira/decisions.py:545 |
| Zadanie z holdem | Widoczny etap to awaiting_decision. Dla proposed lub konfliktu ruch ma właściciel; dla uzupełnienia lub odczytania odpowiedzi — odpowiedzialny, chyba że działa jawne nadpisanie następnego aktora. Historyczne/ zamknięte zadania nie pokazują aktywnego overlayu holdów. |
src/heyaira/decisions.py:630, src/heyaira/task_org.py:121 |
| Bieżące wykonanie i kolejne wysłanie | Hold blokuje ukończenie workflow: wynik pracy może zachować commit, lecz workflow przechodzi do blocked; PASS weryfikatora też nie przyjmuje wyniku. Blokuje nowe oferty, claim i workflow_send. Sam hold nie przerywa procesu agenta w trakcie pracy. |
src/heyaira/workflow.py:421, src/heyaira/workflow.py:522, src/heyaira/workflow.py:726, src/heyaira/execution.py:428 |
| Po odpowiedzi | Hold pozostaje. Koordynator czyta wynik i jawnie usuwa go przez task_decision_hold(held=false); dla zablokowanego workflow ponownie wywołuje workflow_send. Spełnienie required_approvals jest wyliczane przez te same sprawdzenia co decision_check; nie zmienia etapu i nie wykonuje czynności. |
src/heyaira/decision_answers.py:174, src/heyaira/decisions.py:560, src/heyaira/decisions.py:630, src/heyaira/workflow.py:522, tests/test_decisions_holds.py:67 |
Co pozostaje w historii i logach¶
| Zapis | Zawartość i ograniczenia | Źródło |
|---|---|---|
| Propozycja i zdarzenia | Autor ustalony przez serwer, hash treści; w zdarzeniach akcja, opcja/notatka, osoba lub principal delegata, klucz/delegacja, kanał, czas; przy used zadanie i wersja. Triggery blokują edycję historii i drugą terminalną odpowiedź. |
migrations/054_decisions.sql:25, migrations/054_decisions.sql:43, migrations/054_decisions.sql:71, src/heyaira/decision_answers.py:174 |
| Audyt i ponowienia | Audyt zawiera projekt, aktora, operację, cel, request ID i wynik. Zapisy MCP wymagają write_context i klucza idempotencji; ponowienie tego samego wywołania przez ten sam principal zwraca zapisany wynik. Przeglądanie/link nie jest odpowiedzią ani zdarzeniem zgody. |
src/heyaira/server.py:598, src/heyaira/decisions.py:389, src/heyaira/decisions.py:475, src/heyaira/decision_passkeys.py:134, src/heyaira/decision_answers.py:49 |
| Powiadomienia | decision_waiting po propozycji; decision_answered po zatwierdzeniu/odmowie/dopytaniu/odwołaniu; dodanie i odwołanie klucza dla każdego projektu konta. Kopia w projekcie, kopie dla Maców i dostarczenia telefonom powstają transakcyjnie. Treść decyzji w powiadomieniu to pytanie ucięte do 120 znaków, bez opcji; deep link to heyaira://decisions/<id>. To powiadomienie projektu, nie wiadomość dostarczona bezpośrednio do sesji MCP. |
src/heyaira/decisions.py:444, src/heyaira/decision_answers.py:183, src/heyaira/decision_passkeys.py:193, src/heyaira/server.py:1327, src/heyaira/server.py:1339 |
| Indeks startowy | continuity_context.decisions: in_force do 20 wpisów / 4 KB, attention do 50 z jawną flagą obcięcia; pełna decyzja i historia przez decision_get. Token wykonania nie dostaje tego indeksu ani linków; odczyty decyzji filtrują relacje do przydzielonego zadania i wersji. |
src/heyaira/decisions.py:657, src/heyaira/decisions.py:173, src/heyaira/decisions.py:180, src/heyaira/server.py:3712, src/heyaira/server.py:3946 |
| Log dostępu | Filtr Uvicorn pomija URL-e /decide/, które zawierają uchwyty i kody rejestracji. Mod Claude nie przechowuje ani nie wypisuje pobranych linków; skill Codex celowo pokazuje link właścicielowi. |
src/heyaira/decision_web.py:296, clients/claude-mod/hooks/register.tsx:279, clients/codex-plugin/skills/heyaira-decisions/SKILL.md:38 |
Rozjazdy¶
Poniżej są zadania do przekazania koordynatorowi, z parami plik:linia w rewizji
opisanej na początku. Nie utworzono osobnych zadań MCP: token tego wykonania pozwala
oddać RESULT, nie tworzyć zadań. Lista obejmuje znalezione różnice zachowania oraz
luki opisu publicznego; uzgodnienia §12.2 oznaczono osobno. Wskazanie różnicy nie
rozstrzyga, czy należy zmienić kod, czy umowę. D0 i kod pozostają bez zmian.
| ID / zadanie | Specyfikacja lub publiczny opis | Implementacja / rozjazd |
|---|---|---|
| R01 — Uzgodnić interfejs D3 | docs/specs/decisions/D0-spec.md:546, docs/specs/decisions/D0-spec.md:547, docs/specs/decisions/D0-spec.md:1018: Codex ma pokazywać „to samo” co belka/panel Claude, z przyciskiem. |
clients/codex-plugin/.codex-plugin/plugin.json:8, clients/codex-plugin/skills/heyaira-decisions/SKILL.md:34, clients/codex-plugin/build_skill.py:14: plugin dostarcza skill, tekst i link; brak kodu belki/panelu oraz wspólnego renderera D2. |
| R02 — Uzgodnić ceremonię D4 | docs/specs/decisions/D0-spec.md:443, docs/specs/decisions/D0-spec.md:545, docs/specs/decisions/D0-spec.md:1019: natywne assertion, okno web jako fallback. |
ios/HeyAiraBridge/HeyAiraBridge/AppModel.swift:56, ios/HeyAiraBridge/HeyAiraBridge/DecisionAuthSession.swift:13, ios/HeyAiraBridge/HeyAiraBridge/DecisionStore.swift:127: zawsze ASWebAuthenticationSession; brak natywnego providera passkey. |
| R03 — Uzgodnić oznaczenie kanału telefonu | docs/specs/decisions/D0-spec.md:545, docs/specs/decisions/D0-spec.md:1019: odpowiedź telefonu ma channel=ios. |
src/heyaira/decision_web.py:85 nie wysyła channel; src/heyaira/decision_passkeys.py:167 stosuje domyślne web. return=ios steruje wyłącznie callbackiem (ios/HeyAiraBridge/HeyAiraBridge/DecisionModels.swift:263). |
| R04 — Uzgodnić AASA i uprawnienia aplikacji | docs/specs/decisions/D0-spec.md:817, docs/specs/decisions/D0-spec.md:1019: endpoint AASA z webcredentials dla D4. |
Rejestracja tras kończy się na odczytach kanałów (src/heyaira/decision_web.py:379, src/heyaira/server.py:1751); brak trasy AASA w src/. Entitlements zawierają tylko APNs (ios/HeyAiraBridge/HeyAiraBridge/HeyAiraBridge.entitlements:4), bez Associated Domains. To brak w tym repo, nie dowód stanu konfiguracji edge. |
| R05 — Doprecyzować projekty listy mobile | docs/specs/decisions/D0-spec.md:812: „the device’s projects”. |
src/heyaira/decision_web.py:404, src/heyaira/decision_web.py:407, ios/HeyAiraBridge/HeyAiraBridge/BridgeAPIClient.swift:138: tylko projekt tokenu i urządzenie aktywne w nim; nie agregacja projektów urządzenia. |
| R06 — Uzgodnić ogólną odmowę | docs/specs/decisions/D0-spec.md:359, docs/specs/decisions/D0-spec.md:473: strona zawsze oferuje ogólne „Reject” obok wyboru opcji. |
src/heyaira/decision_web.py:242: ogólne „Reject” tylko bez dostępnej opcji authorizes=false; z taką opcją dostępna jest jedynie odmowa nazwaną opcją. Endpoint nadal przyjmuje odmowę bez option_id (src/heyaira/decision_answers.py:101). |
R07 — Uzgodnić odmowę stale na iPhone |
docs/specs/decisions/D0-spec.md:219, docs/specs/decisions/D0-spec.md:899: stale można odrzucić przez link. |
ios/HeyAiraBridge/HeyAiraBridge/DecisionModels.swift:297, ios/HeyAiraBridge/HeyAiraBridge/DecisionModels.swift:303, ios/HeyAiraBridge/HeyAiraBridge/DecisionViews.swift:135: stale nie ma przycisków ani drogi do linku na ekranie aplikacji. Serwer dopuszcza odmowę (src/heyaira/decision_answers.py:113). |
R08 — Poprawić zgodność typu authorizes w D4 |
docs/specs/decisions/D0-spec.md:353: options[].authorizes jest bool. |
ios/HeyAiraBridge/HeyAiraBridge/DecisionModels.swift:34, ios/HeyAiraBridge/HeyAiraBridge/DecisionModels.swift:53, ios/HeyAiraBridge/HeyAiraBridge/DecisionModels.swift:207: model oczekuje String; bool z serwera daje nil. Przyciski pokazują label bez rozróżnienia odmowy; właściwą akcję rozstrzyga dopiero strona (src/heyaira/decision_web.py:80). |
| R09 — Zsynchronizować §10.4 z przyjętym §12.2 | docs/specs/decisions/D0-spec.md:965 wymaga nazwanego zadania, docs/specs/decisions/D0-spec.md:969 opisuje overlay dla każdego holdu. §12.2 dopuszcza zmianę tych zasad (docs/specs/decisions/D0-spec.md:1078, docs/specs/decisions/D0-spec.md:1083). |
src/heyaira/decisions.py:553 dopuszcza null przy zawierającym zakresie i usunięcie istniejącego powiązania po zmianie tagów; src/heyaira/decisions.py:647 ukrywa hold zamkniętego zadania, a src/heyaira/decisions.py:374 odrzuca nowy. Wybrane i opisane w docs/specs/decisions/D1a-implementation.md:12; rozjazd starszego tekstu, nie niezaimplementowany warunek wejścia. |
| R10 — Uzgodnić komunikaty o wznowieniu | docs/specs/decisions/D0-spec.md:962, docs/specs/decisions/D0-spec.md:990: hold usuwa koordynator, a potem ponownie wysyła workflow. |
src/heyaira/decision_web.py:259, ios/HeyAiraBridge/HeyAiraBridge/DecisionViews.swift:257 mówią, że sesja została powiadomiona i może kontynuować. src/heyaira/decision_answers.py:183 tylko kolejkuje powiadomienie projektu, nie wiadomość do sesji; hold pozostaje (tests/test_decisions_holds.py:69). Komunikat pomija wymagany ruch koordynatora. |
| R11 — Wyjaśnić legacy memory i decyzje obowiązujące | docs/concepts/durable-state.md:5, docs/concepts/durable-state.md:26: „decision” to zaakceptowany kierunek w pamięci; brak oddzielnego cyklu propozycji/odpowiedzi. |
src/heyaira/server.py:3828 wymaga dla notatki jedynie rationale, bez passkey; obowiązywanie wylicza osobna tabela (src/heyaira/decisions.py:71, migrations/054_decisions.sql:2). Luka publicznego opisu: zapis notatki nie nadaje in_force. |
| R12 — Uzupełnić publiczny indeks ciągłości | docs/CONTINUITY_PROTOCOL.md:32, docs/CONTINUITY_PROTOCOL.md:47: opis decyzji przez indeks pamięci i memory_get, bez indeksu obowiązywania. |
src/heyaira/server.py:4020, src/heyaira/server.py:4025, src/heyaira/decisions.py:682, src/heyaira/decisions.py:693: osobne decisions.in_force, attention, limity i flagi obcięcia. Publiczny opis nie obejmuje tych pól. |
| R13 — Uzupełnić publiczny opis powiadomień | docs/reference/notifications.md:3, docs/reference/notifications.md:9, docs/reference/notifications.md:25: tabela typów nie zawiera zdarzeń decyzji ani kluczy. |
src/heyaira/server.py:1329, src/heyaira/decision_answers.py:183, src/heyaira/decision_passkeys.py:200: cztery typy decision_*, rzeczywiście kolejkowane. Luka dokumentacji, nawet gdy kontrola curated labels przechodzi. |
| R14 — Rozdzielić uprawnienia odczytu i użycia | docs/reference/mcp-tools.md:12, docs/reference/mcp-tools.md:52: każdy wymieniony scope jest wymagany; przy decision_check podano razem tasks:read i tasks:write. |
src/heyaira/server.py:3678, src/heyaira/server.py:3680: odczyt wymaga tylko tasks:read; tasks:write jest sprawdzane dodatkowo wyłącznie przy use=true. Kontrola zgodności tabeli sprawdza sumę scope'ów, nie ich warunkowość. |
| R15 — Uzgodnić kompletność list D2/D4 | docs/specs/decisions/D0-spec.md:545, docs/specs/decisions/D0-spec.md:546, docs/specs/decisions/D0-skill.md:6: kanały pokazują listę, kanoniczny skill przechodzi wszystkie kursory. |
clients/claude-mod/hooks/register.tsx:21, clients/claude-mod/hooks/register.tsx:98, clients/claude-mod/hooks/register.tsx:159: limit 10 stron z ostrzeżeniem; ios/HeyAiraBridge/HeyAiraBridge/DecisionStore.swift:34, ios/HeyAiraBridge/HeyAiraBridge/DecisionStore.swift:84, ios/HeyAiraBridge/HeyAiraBridge/BridgeAPIClient.swift:139: limit 500 pozycji, a pozostały kursor znika bez ostrzeżenia. Decyzja z dalszej strony nie zostanie otwarta z push. |
| R16 — Doprecyzować licznik belki D2 | docs/specs/decisions/D0-spec.md:546, docs/specs/decisions/D0-spec.md:1017: belka z liczbą nieodpowiedzianych / open decyzji. |
src/heyaira/decisions.py:581 zalicza stale i blokujące lapsed do open; clients/claude-mod/hooks/format.ts:95, clients/claude-mod/hooks/format.ts:138 wyłączają je z total, a clients/claude-mod/hooks/register.tsx:340 ukrywa belkę przy zerowym total. Panel nadal zawiera „Do uzupełnienia”. |
| R17 — Oznaczyć treść autora na stronie | docs/specs/decisions/D0-spec.md:626: label, konsekwencje i uzasadnienie mają być oznaczone jako tekst proponującego, oddzielnie od interpretacji grantu. |
src/heyaira/decision_web.py:180, src/heyaira/decision_web.py:192, src/heyaira/decision_web.py:199: strona pokazuje te pola bez oznaczenia ich autorstwa; grant ma osobny nagłówek „as the server reads it”. Hash nadal wiąże przechowywaną treść, lecz nie potwierdza prawdziwości opisu skutków. |
Źródła¶
Pary plik:linia odnoszą się do powyższej rewizji. Odczytane pliki źródłowe,
testy i opisy użyte do porównania (test odczytany nie oznacza testu uruchomionego):
- Kontekst:
AGENTS.md,README.md,docs/ARCHITECTURE.md,docs/index.md,mkdocs.yml,pyproject.toml,docs-requirements.txt. - Umowa i rola:
docs/specs/org-v1/K0-work-contract.md,docs/specs/org-v1/K0-roles.md. - Decyzje:
src/heyaira/decisions.py,src/heyaira/decision_answers.py,src/heyaira/decision_passkeys.py,src/heyaira/decision_web.py. - Powiązania serwera (odczytane fragmenty):
src/heyaira/server.py,src/heyaira/admin.py,src/heyaira/workflow.py,src/heyaira/execution.py,src/heyaira/task_org.py,src/heyaira/bridge_reads.py,src/heyaira/bridge.py. - Baza:
migrations/054_decisions.sql,migrations/055_decision_passkeys.sql. - Claude:
clients/claude-mod/README.md,clients/claude-mod/hooks/register.tsx,clients/claude-mod/hooks/format.ts. - Codex:
clients/codex-plugin/.codex-plugin/plugin.json,clients/codex-plugin/header.md,clients/codex-plugin/build_skill.py,clients/codex-plugin/skills/heyaira-decisions/SKILL.md. - iPhone:
ios/HeyAiraBridge/HeyAiraBridge/DecisionModels.swift,ios/HeyAiraBridge/HeyAiraBridge/DecisionStore.swift,ios/HeyAiraBridge/HeyAiraBridge/DecisionAuthSession.swift,ios/HeyAiraBridge/HeyAiraBridge/DecisionViews.swift,ios/HeyAiraBridge/HeyAiraBridge/BridgeAPIClient.swift,ios/HeyAiraBridge/HeyAiraBridge/AppModel.swift,ios/HeyAiraBridge/HeyAiraBridge/HeyAiraBridgeApp.swift,ios/HeyAiraBridge/HeyAiraBridge/HeyAiraBridge.entitlements. - Specyfikacje:
docs/specs/decisions/D0-spec.md,docs/specs/decisions/D0-skill.md,docs/specs/decisions/D1a-implementation.md,docs/specs/decisions/D1b-implementation.md. - Publiczne opisy:
docs/concepts/durable-state.md,docs/CONTINUITY_PROTOCOL.md,docs/reference/mcp-tools.md,docs/reference/notifications.md,docs/agents/continuity-contract.md,docs/ROADMAP.md,docs/getting-started/overview.md,docs/operations/documentation-workflow.md. - Testy:
tests/test_decisions.py,tests/test_decisions_holds.py,tests/test_decisions_e2e.py,tests/test_decisions_webauthn.py,tests/test_codex_plugin.py,tests/test_docs_contract.py.
Wyniki sprawdzeń i odwołania do wcześniejszych RESULT: dowody zadania.