Commit Graph
227 Commits
Author SHA1 Message Date
marcopanandClaude Opus 4.8 1f9818c50f fix(gate): guard the TUI-only "Esc" notice on ctx.mode, not ctx.hasUI
reLoop's "Esc non chiude il gate..." warning is terminal-specific. On pi 0.73
ctx.hasUI was false in RPC, so `if (ctx.hasUI)` effectively meant "TUI only". On
pi >=0.80 hasUI is true in RPC too (dialog-capable UI via the bridge), so the
notice leaked to the browser on any invalid gate response. Guard on
ctx.mode === "tui" to restore the original intent. The fake pi runtime gains
mode:"tui" so the roundtrip test still exercises the notice.

Audit of the other 5 ctx.ui.notify: left as-is. They are valid in both live
modes (TUI and RPC, both hasUI=true) and the gate cannot run headless
(emitAndWait needs a UI), so a guard would be dead code. Their dual-mode
rationalization belongs with the future present() work (tracked in the eval doc).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:21:57 +02:00
marcopanandClaude Opus 4.8 0afa9a2f80 docs(pi): correct dual-mode gate eval — hasUI polarity, info/freetext wiring, citations
- #1 hasUI: real 0.80.3 comment is "true in TUI and RPC modes" (doc had the old
  0.73.1 "false in print/RPC"). hasUI no longer distinguishes TUI from RPC, so it
  is NOT a fallback for the interactive branch — only ctx.mode === "tui" is.
- #2 info/freetext: buildInfoRequest exists in builders.js but is NOT wired into
  tht-gate.js (imports only select/multiselect/artifact-gate). info notices are
  hand-written ctx.ui.notify; freetext is a control, not a descriptor. Table now
  lists only the 3 real present() descriptors.
- #3 cite the REWRITE banner (tht-gate.js:8-10), not :227; id-match quoted verbatim.
- #4 new "Note implementative": 227 comment, 4/6 unguarded notify, and the
  ctx.hasUI guard migration side-effect (now fires in RPC on 0.80.3).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:13:26 +02:00
marcopanandClaude Opus 4.8 be02e96f9e chore(pi): consolidate 0.80.3 migration — align extension + docs to @earendil-works
- aritmolab-provider.js: import pi-ai from @earendil-works (was @mariozechner).
  Verified live that the aritmolab/qwen provider still registers under pi 0.80.3
  (get_available_models -> aritmolab, deepseek, zai). Removes the dual-package
  reliance on the frozen @mariozechner install still on disk for rollback.
- docs/general/pi-configuration.md: built-in models package is @earendil-works/pi-ai

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 13:23:46 +02:00
marcopanandClaude Opus 4.8 b35c4b5692 docs(pi): migrate runtime to @earendil-works@0.80.3; update dual-mode gate eval
- live pi repointed 0.73.1 (@mariozechner, frozen) -> 0.80.3 (@earendil-works);
  validated via API/RPC surface diff (stable+additive) + model-matrix smoke
  (GLM 5.2 new+resume CHAINED)
- PROJECT_STATE: item 6 migration note (supersedes the 0.79.4 references)
- dual-mode gate eval: integrate review points (#3,#5,#7,#8,#9,#10) and flip #1
  to ctx.mode === "tui" (0.80.3 exposes ctx.mode: tui|rpc|json|print)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:51:56 +02:00
marcopanandClaude Opus 4.8 a0a503b721 fix(gate): coerce stringified object params; block model edits to gate code
Some models (GLM 5.2) send object params (reviewer_confirm's artifact,
write_schema_linking's schema_linking) as JSON-encoded strings. These failed
TypeBox validation before execute(), making the model retry in an unbounded loop
(observed ~2100s hang). jsonObjectOrSelf() coerces them back to objects in
prepareReviewerArguments and write_schema_linking.

Also close an anti-bypass gap: pi's write/edit tools were unrestricted on the gate
code, so a looping model actually patched tht-gate.js. GATE_CODE_FILES now blocks
any write under .pi/extensions. Requires a pi restart to take effect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:28:45 +02:00
marcopanandClaude Opus 4.8 f1b071d165 feat(shell): 30/55/15 layout, formatted activity log, instant resume, stop confirmation
Left panels 30vw / central 55% / right rail 15vw, minimal padding. Model-activity
log and documents render via .thot-prose; decisions become hairline rows with
semantic type chips. Resume switches the view optimistically (instant feedback).
The Stop button now asks for confirmation before interrupting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:15:48 +02:00
marcopanandClaude Opus 4.8 a719ad5990 feat(viewer): artifact modal renders structured text, never raw JSON
ArtifactView's fallback (StructuredValue) turns any object/array into labelled
sections, bullet lists and paragraphs (strings as markdown). Verified against the
real F1 gate (kind:"text", {recap, chiarimenti_risolti[], ...}). MarkdownView
uses the real .thot-prose class (Tailwind Typography is not installed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:15:48 +02:00
marcopanandClaude Opus 4.8 cec6620c00 feat(widgets): redesign gate widgets — readable hierarchy, prominent select-all, styled controls
Titles + intro read as a clear prompt (comfortable line length), options as
spaced choice rows, Other/Back/Exit as discreet secondary controls under a
divider. Multiselect gets a prominent Select all/Deselect all at the head of the
list with a live count.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:15:48 +02:00
marcopanandClaude Opus 4.8 56ed8b29bd feat(workflow-bar): processing-only elapsed timer + optimistic phase paint on resume
Timer now accumulates only while the harness works, pausing while a gate awaits
the reviewer and freezing when finalized (keyed per session, in-memory). Resume
now colours the re-entry phase immediately from the manifest's phase (1..8),
mirroring the F1 paint for new questions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:13:02 +02:00
marcopanandClaude Opus 4.8 e4ada07dab feat(viewer): erDiagram shows real column types when present; ArtifactView accepts a {content} sql wrapper
erDiagram reads data_type/type from the candidate (top-level or signals),
falling back to the generic 'col' token Mermaid needs — real types render as
soon as schema_linking.json carries them. ArtifactView gains a defensive
{content} fallback for sql-kind artifacts, verified against real session shapes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:13:02 +02:00
marcopanandClaude Opus 4.8 c3e8f14ad9 test(gate): clarify the 'altrove' first-token guard comment
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:13:02 +02:00
marcopan 3f852fd817 feat(workflow-bar): total elapsed timer after the phase circles 2026-07-03 13:26:25 +02:00
marcopan e630ac98f9 feat(workflow-bar): optimistic F1 at start; all-green when session finalized 2026-07-03 13:22:09 +02:00
marcopan 37b3eb45e9 feat(gate): render reviewer artifacts in a 90% modal (fix empty artifact.data gate) 2026-07-03 13:17:54 +02:00
marcopan 0975a8a72b feat(viewer): ArtifactView routes artifact.data by kind (schema/sql/cte/question) 2026-07-03 13:13:51 +02:00
marcopan 893e9e4059 feat(viewer): schema linking renders a Mermaid erDiagram (tables + relations) 2026-07-03 13:09:09 +02:00
marcopan 168a72372b fix(gate): robust isReserved strips model Altro/other variants (no duplicate free-text option) 2026-07-03 13:05:21 +02:00
marcopanandClaude Opus 4.8 3de1a784ce docs(plan): implementation plan for workflow UI fixes (6 tasks, TDD)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 13:01:31 +02:00
marcopanandClaude Opus 4.8 3c198ec775 docs(spec): design for workflow UI fixes (phase circles, timer, artifact modal, Altro dedup)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 12:45:05 +02:00
marcopanandClaude Opus 4.8 b043293baf fix(gate): stop injecting the redundant Altro option on select gates
buildSelectRequest injected an `altroOption` ({id:"other", opens:freetext}) into the
select descriptor, but SelectWidget/MultiselectWidget never route option.opens — so it
rendered as an inert "Altro — specifica…" button next to the working reserved
"Other — specify" control (which now owns free-text since the reviewer-gate-ux fix).
Remove the injection, the now-unused altroOption()/ALTRO_LABEL, and the unused
allow_other flag from both builders (no frontend consumer). Free-text stays offered on
every gate via the reserved "Other" control. The ArtifactGateWidget opens/LinkageHost
linkage (reject-with-reason capability) is intentionally kept — it is a separate,
tested feature, not the injected duplicate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 19:10:01 +02:00
marcopanandClaude Opus 4.8 25ab37d0fe fix(frontend): disable 'Altro' Send until non-whitespace text (no empty freetext)
Backlog T2 from the reviewer-gate-ux review: the Send button on the reserved
"Other — specify" textarea emitted control:freetext with an empty payload when
clicked on an empty/whitespace field. Guard with disabled={!text.trim()}.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 18:52:12 +02:00
marcopan 78518210a0 docs(skill): document empty-memory auto-advance (no empty checklist) in Phase 2 2026-07-02 18:39:12 +02:00
marcopan 0a76103c35 fix(gate): empty memory phase shows a notice and auto-advances instead of an empty checklist 2026-07-02 18:34:17 +02:00
marcopan 644634d492 fix(gate): reviewer_confirm requires explicit approve; free-text is actionable, not accidental approve 2026-07-02 18:30:14 +02:00
marcopan 2633b46199 fix(gate): buildArtifactGate emits approve/reject options so the gate renders a forward button 2026-07-02 18:27:11 +02:00
marcopan 541df01684 fix(frontend): 'Other — specify' opens a text field and emits control:freetext 2026-07-02 18:24:02 +02:00
marcopan eacc441a4f fix(frontend): render Back/Exit/Other controls on the multiselect widget 2026-07-02 18:20:25 +02:00
marcopanandClaude Opus 4.8 daceda3555 docs(plan): reviewer gate UX fixes implementation plan; align spec Part 4 to ctx.ui.notify
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 17:16:57 +02:00
marcopanandClaude Opus 4.8 91a6806617 docs(spec): reviewer gate UX fixes — multiselect hatches, gate forward button, Altro text, empty-memory auto-advance
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 17:10:15 +02:00
marcopanandClaude Sonnet 5 023c69d752 fix(frontend,harness): phase-stepper wiring, central tail, activity-panel markdown
- WorkflowBar: center the phase pills (add justify-center).
- tht-gate.js: the gate was sending the descriptive phase name (e.g.
  "chiarimento") instead of the workflow.yaml id ("F1") in the widget's
  `phase` field, so the frontend's F1..F8 match never hit and pills never
  lit up. Rename phaseName -> phaseId, return p.id.
- CentralStatus: expand the live "working" tail from a single truncated
  line to up to 5 lines (line-clamp-5 safety net for unbroken paragraphs).
- ModelActivityPanel: render the streamed tail through react-markdown +
  remark-gfm instead of raw per-line <p> tags, so emphasis/headings render
  and blank-line paragraph breaks (previously stripped) are preserved;
  tail-cut now operates on paragraphs instead of physical lines.

Updated tests accordingly (WorkflowBar/CentralStatus/ModelActivityPanel/
AppShell.session-mgmt); full frontend suite (98/98) + harness gate node
tests (34/34) + tsc -b pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 15:53:31 +02:00
marcopanandClaude Sonnet 5 7c417d4cf1 docs: set up MkDocs site with technical/general docs split
Add mkdocs.yml (windmill theme, mermaid2, matching ~/Chirone/chirone/etl
setup) with nav split into "ThothII (Documentazione Tecnica)" — architecture
overview, existing design specs/plans, reports — and "Considerazioni
Generali" for cross-project notes.

Add docs/general/pi-configuration.md explaining Pi's three model-resolution
tiers (built-in, user models.json, project extension) and where GLM/DeepSeek/
Qwen each sit. Add docs/architecture/overview.md synthesizing the ThothII
architecture for the doc site. Relocate the L2 run report into docs/reports/.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 12:37:26 +02:00
marcopanandClaude Fable 5 4479683cf4 chore(pi): scope AritmoLab provider to project, drop Gemma model
Move the AritmoLab provider (Qwen) into harness/.pi/extensions/ so it is
auto-discovered only when Pi runs with cwd=harness, keeping it project-local.
GLM (~/.pi/agent/models.json) and DeepSeek (built-in) stay user-wide. File is
.js (not .mjs) because Pi extension auto-discovery matches only /\.(ts|js)$/.

Removes the gemma4-26b-a4b model (404 at the endpoint) from both the provider
and the model-matrix default list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 11:49:11 +02:00
marcopanandClaude Opus 4.8 cdaca9b87d docs(state): workflow contract hardening landed (F6 fix, schema_linking writer, SKILL contract)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 23:39:10 +02:00
marcopanandClaude Opus 4.8 3dadc6fbb5 docs(skill): F7 is two-step — kind:"sql" records, kind:"phase" advances
The cheat-sheet, Discipline 2, and Phase 7 said F7 closes with
reviewer_confirm kind:"sql" — but the gate's kind:"sql" only records
sql_approved:phase:7; F7 is not in _AUTO_ADVANCE_PHASES, so advancing to
F8 still needs reviewer_confirm kind:"phase" (mirrors F6). Same
record-vs-advance trap this branch removes elsewhere.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 19:55:23 +02:00
marcopanandClaude Opus 4.8 01de6f330f docs(skill): correct phase-advance contract + add phase cheat-sheet
F3/F4 close with reviewer_confirm kind:'phase' (they do NOT auto-advance);
advance:true only auto-advances F2-empty/F6-skip; rewrite_question belongs
to F3 not F1; F4 uses the new write_schema_linking tool with the documented
SchemaLinking shape. Adds a per-phase artifact/close cheat-sheet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:55:49 +02:00
marcopanandClaude Opus 4.8 20bc3de950 feat(gate): write_schema_linking tool (validated F4 artifact via CLI)
tht() gains an optional stdin arg; the tool pipes the schema-linking
object to 'tht session set-schema-linking --file -', which validates
against SchemaLinking and returns the exact error on failure — so the
model stops hand-writing the artifact and validating with ad-hoc python.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:49:18 +02:00
marcopanandClaude Opus 4.8 00777922d8 feat(cli): 'tht session set-schema-linking' (file/stdin, validated)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:44:36 +02:00
marcopanandClaude Opus 4.8 92caaac18d feat(store): set_schema_linking validates then writes the F4 artifact
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:40:04 +02:00
marcopanandClaude Opus 4.8 160d7f075e fix(gate): F6 approves each CTE by name, not 'phase:6'
reviewer_confirm kind:'cte_result' registered cte_approved --subject
phase:6, which decision_cmd rejects (exit 5) and next_cte never
recognizes — dead-ending F6. Derive the CTE name from 'tht cte next'
(plan-order single source of truth) and approve by name. sql path
(sql_approved:phase:N) unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:34:54 +02:00
marcopanandClaude Opus 4.8 47a52170ce feat(cte): add 'tht cte next' — first unapproved plan CTE
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:29:52 +02:00
marcopanandClaude Opus 4.8 0193341b93 docs(plan): workflow contract hardening — 7-task TDD plan
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:26:59 +02:00
marcopanandClaude Opus 4.8 d5af7b5d65 docs(spec): workflow contract hardening (F3 advance, F6 cte_approved, schema_linking writer)
Design doc for three coordinated harness fixes derived from the
2026-06-30-165708 session analysis: correct SKILL.md phase-advance
contract, fix the F6 cte_approved subject bug, and add a
tht-mediated schema_linking.json writer/validator.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:19:09 +02:00
marcopanandClaude Opus 4.8 7895819884 docs(state): mark UI-redesign + resume plan COMPLETE (D-G shipped)
All workstreams D, E, B, C, F, A, G done and pushed; resume cold-start stall
resolved (open-item #1). Refresh the Git section: main @ cbb8e18, the three
stale merged branches deleted, only main remains. Clean handoff snapshot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:57:29 +02:00
marcopanandClaude Opus 4.8 cbb8e184f1 feat(harness): cross-model behavior matrix (G) — harness + results
Tier 1 (clean-room first-turn harness, harness/scripts/model-matrix.mjs):
kickoff + resume chain in-turn on ALL available models — zai/glm-5.2,
deepseek/deepseek-v4-{pro,flash}, aritmolab/qwen3.6-35b-a3b, zai/glm-4.5-air.
The resume cold-start stall recurs on none (closes A's cross-model robustness).
aritmolab/gemma4-26b-a4b is a 404 at the endpoint (listed but not served) — an
availability gap classified as MODEL_ERROR, not a workflow issue.

Tier 2 (live, baseline zai/glm-5.2): F single-select auto-confirm verified
end-to-end — answering the first reviewer_select persisted a concept_clarified
decision (review_decisions.jsonl 0->1) with no follow-up confirmation gate.
Closes F's deferred live check.

No prompt hardening needed. Results in the G plan doc + memory. Throwaway psd
sessions used and deleted; real sessions untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:46:55 +02:00
marcopanandClaude Opus 4.8 e8cdd0037c docs(plan): scope workstream G (cross-model behavior matrix)
Actionable scoping for the final workstream: a two-tier method (clean-room
first-turn harness generalised from the A2 repro-driver for cheap kickoff/resume
signals; sparing full Playwright F1 runs for the gate round-trip) over the
configured models (GLM 5.2 baseline, Deepseek V4, Qwen3.6, + breadth). Folds in
F's deferred single-select live check and A's resume-on-weaker-models check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:20:46 +02:00
marcopanandClaude Opus 4.8 0a13f71b4d feat(resume): Resume in the kebab menu (A1) + harden the resume kickoff (A2)
A1 — SessionMenu gains a Resume item, gated to status!=="finalized" && !archived
(matching the backend's 409 read-only guard), wired in AppShell to doResume ->
POST /sessions/:id/resume. SessionMenu.test.tsx (3 tests); frontend 96/96, tsc clean.

A2 — diagnosis-first clean-room repro driving `pi --mode rpc` with the backend's
exact resume handshake shows the cold-start stall NO LONGER reproduces on pi
0.79.4 (8/8 chained into `tht session show` + `read SKILL.md` in-turn, fresh and
partway sessions). The earlier narrate-and-stop predates the pi upgrade.
Defense-in-depth anyway: RIPRENDI_KICKOFF hardened to force the in-turn tool call
(gate_resume_kickoff.test.js + live regression 2/2). Gate JS 34/34.

PROJECT_STATE open-item #1 (resume stall) flipped to RESOLVED; cross-model resume
robustness folded into workstream G.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:19:10 +02:00
marcopanandClaude Opus 4.8 cef9ae4368 feat(harness): single-select answers auto-confirm (reviewer_select persists)
F — reviewer_select options may now carry a `decision` payload {type, subject,
detail?, rationale?} plus an optional `advance`. Picking such an option IS the
confirmation: the gate persists it directly (tht decision add) and optionally
advances, with no redundant reviewer_decide/reviewer_confirm follow-up gate.
Options without a payload stay ask-only; back/exit/Other never persist.

Pure logic extracted + exported for unit tests: resolveSelectOutcome (classifies
the response) and decisionAddArgs (shared with reviewer_decide, DRY). Gate JS
suite 33/33 (gate_select_decision.test.js, +5); harness pytest 269 unchanged.

Contract docs updated together: reviewer_select tool description, SKILL.md
(widget summary, disciplines 2-3, Phase-1 single-pick), and the CLAUDE.md gate
note. Live verification (model truly emits reviewer_select+decision, decision in
review_decisions.jsonl, no follow-up gate) deferred to workstream G — it is
model-behavior-dependent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:01:50 +02:00
marcopanandClaude Opus 4.8 b056ff334f feat(frontend): phase progress dots (B) + compact sidebar redesign (C)
B — WorkflowBar renders F1..F8 as colored ring-dots (no phase-name text):
green=done, amber=running (subtle pulse), red=error, gray=pending; green
connectors lead the active dot, each dot carries data-state. Lightweight
error signal: sessionStore gains `phaseError`, set when an info event has
level=error during the active phase, cleared on the next ui_request.

C — denser single-line session rows (inline status dot + name, py-1), a
3-level type hierarchy (L1 SESSIONS / L2 section+group headers / L3 names),
and the "No group" label removed (ungrouped render after the last group,
guarded so the empty-state still teaches when there are zero groups).

Live-verified with Playwright (all four dot states, sidebar hierarchy, and
E's deferred activity-panel check). Frontend 93/93, tsc -b clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 17:53:29 +02:00
marcopanandClaude Opus 4.8 2e09c88f78 docs(state): record UI-redesign progress (D+E done; B/C/F/A pending)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 16:46:50 +02:00
marcopanandClaude Opus 4.8 0eeb3f7522 feat(frontend): rotating activity icon + 5-line expandable activity panel
- CentralStatus: replace the red pulsing dot at the start of the "working" line
  with the rotating WorkingSpinner, now a button that opens the model-activity
  panel (onOpenActivity). WorkingSpinner is extracted to its own module (was
  local to AppShell).
- ModelActivityPanel: show the last 5 lines of the model-stream tail (refreshing
  as the stream grows) with an expand toggle to the full stream, replacing the
  unbounded full transcript.
- AppShell: drop the separate spinner button (the inline icon is now the single
  trigger) and the local WorkingSpinner def.
- Remove the now-orphaned Transcript.tsx (its only consumer was the panel).

TDD: CentralStatus + ModelActivityPanel tests RED->GREEN; frontend suite 87/87;
tsc clean. Live visual verification pending (to do with the B/C frontend pass).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 16:26:43 +02:00