Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67ee52624c | ||
|
|
0d2e573e0d | ||
|
|
bd416f7327 | ||
|
|
23e52c80de | ||
|
|
84084bba37 | ||
|
|
efd7d788d9 | ||
|
|
b1c510a097 | ||
|
|
5f3680a0fb | ||
|
|
4ff91e8d6e | ||
|
|
5f3a7f5975 | ||
|
|
043ffdfad6 | ||
|
|
6a4634dcf1 | ||
|
|
84804be9f8 | ||
|
|
c3caba94dd | ||
|
|
b1723c34c4 | ||
|
|
d6cdffea62 | ||
|
|
49333a2d35 | ||
|
|
b006b94479 | ||
|
|
bdcd8fcd28 | ||
|
|
cf90c1bd51 | ||
|
|
571a4bcaa2 | ||
|
|
9051463654 | ||
|
|
26c5605ff7 | ||
|
|
3535fda958 | ||
|
|
2953f6b608 | ||
|
|
45db3a239b | ||
|
|
7d826e46c0 | ||
|
|
648434a32e | ||
|
|
023b822f83 | ||
|
|
d8a29bfbdd |
@@ -30,3 +30,7 @@ coverage/
|
||||
data/
|
||||
sessions/
|
||||
workspace-registry/
|
||||
|
||||
.tht/
|
||||
|
||||
deploy/local/
|
||||
|
||||
@@ -7,6 +7,11 @@ on:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "mkdocs.yml"
|
||||
- "scripts/build-docs.sh"
|
||||
- "scripts/verify-public-docs.py"
|
||||
- "scripts/test-verify-public-docs.py"
|
||||
- "scripts/verify-auth-docs.py"
|
||||
- "scripts/test-verify-auth-docs.py"
|
||||
- "docs/requirements.txt"
|
||||
- ".gitea/workflows/publish-docs.yml"
|
||||
workflow_dispatch:
|
||||
@@ -34,14 +39,25 @@ jobs:
|
||||
with:
|
||||
python-version: "3.x"
|
||||
cache: pip
|
||||
cache-dependency-path: docs/requirements.txt
|
||||
cache-dependency-path: docs/requirements.lock
|
||||
|
||||
- name: Install MkDocs dependencies
|
||||
run: python -m pip install -r docs/requirements.txt
|
||||
run: python -m pip install -r docs/requirements.lock
|
||||
|
||||
- name: Test public documentation boundary
|
||||
run: python scripts/test-verify-public-docs.py
|
||||
|
||||
- name: Test current authentication documentation
|
||||
run: |
|
||||
python scripts/verify-auth-docs.py auth
|
||||
python scripts/verify-auth-docs.py dwh
|
||||
python scripts/test-verify-auth-docs.py auth
|
||||
python scripts/test-verify-auth-docs.py dwh
|
||||
|
||||
- name: Build documentation
|
||||
# Some documented source files intentionally live outside docs/.
|
||||
run: mkdocs build
|
||||
run: |
|
||||
mkdocs build --strict
|
||||
python scripts/verify-public-docs.py
|
||||
|
||||
- name: Publish generated site to the pages branch
|
||||
working-directory: site
|
||||
|
||||
@@ -46,6 +46,7 @@ deploy/secrets/*
|
||||
# Per-installation configuration generated by `tht setup` (examples stay tracked).
|
||||
deploy/*/thothii-installation.yaml
|
||||
deploy/*/operator.env
|
||||
deploy/*/auth/
|
||||
deploy/*/generated/
|
||||
deploy/*/secrets/*
|
||||
!deploy/*/secrets/.gitkeep
|
||||
|
||||
@@ -98,8 +98,18 @@ frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness →
|
||||
- **`tht`'s `-c`/`--config` is a PER-COMMAND option** — it must follow the subcommand, never
|
||||
precede it (`ThtRunner.buildArgv` enforces this; prepending caused live 500s).
|
||||
- **`--json` output must be pristine** (only valid JSON on stdout) — used as a machine contract.
|
||||
- **UI strings are English; document *content* stays the workspace language** (Italian for
|
||||
`psd`) because it's the real data. Only chrome/labels are English.
|
||||
- **Localization:** deterministic UI uses the EN/IT catalogs with English fallback;
|
||||
model interaction uses the session manifest's immutable `interaction_language`.
|
||||
Workspace content, SQL, and identifiers remain unchanged. For shell modes, portal
|
||||
integration, or translations, read `docs/operations/shell-and-localization.md`.
|
||||
- **Server deployment:** for the coordinated ThothII/Omics upgrade, follow
|
||||
`docs/operations/server-codex-handoff.md`; it supersedes earlier Omics delivery
|
||||
instructions. Omics source integration uses GitHub with no repository relay prerequisite.
|
||||
- **Server identity:** for portal login/logout, proxy headers, or Omics deploy, read
|
||||
`docs/install/authentication-upstream.md` before changing authentication. Omics
|
||||
uses embedded/upstream, not a second ThothII OIDC login. Full/embedded rendering
|
||||
is documented in `docs/architecture/application-shell.md`; release acceptance
|
||||
is in `docs/testing/authentication-manual-acceptance.md`.
|
||||
- **Workspace schema v4** defines workspace identity and optional Evidence only. PostgreSQL Metadata
|
||||
Catalog owns database identity, binding, schema, descriptions, sensitivity, and relationships;
|
||||
embedding/model facts come from the installation catalog. The legacy `harness/workspaces/*.yaml` runtime snapshots still use
|
||||
|
||||
@@ -595,6 +595,49 @@ essere ripristinabile con refresh e cronologia e non contiene valori transitori
|
||||
un portale host. Conserva la propria gerarchia funzionale, ma deve rispettare la geometria,
|
||||
l'autenticazione e le regole responsive del portale host.
|
||||
|
||||
**Full Thoth Shell** — L'esperienza Thoth autonoma che possiede il proprio header e il proprio
|
||||
layout di pagina. Non replica la navigazione amministrativa del portale host e non dipende dal suo
|
||||
template visuale.
|
||||
|
||||
**Shell mode** — La scelta di installazione fra `embedded` e `full`. Determina chi possiede il
|
||||
chrome globale, i comandi di identità e le integrazioni visuali, ma non cambia il workflow o la
|
||||
persistenza delle sessioni.
|
||||
|
||||
**Fullscreen state** — Lo stato temporaneo in cui il documento applicativo occupa il fullscreen
|
||||
del browser. È distinto da `Shell mode`: una Full Thoth Shell può essere aperta senza fullscreen;
|
||||
il passaggio è attivato da un comando esplicito e può essere annullato con la stessa azione o con
|
||||
il comando nativo del browser.
|
||||
|
||||
**Portal Shell Adapter** — Il confine sostituibile che traduce lo stato e i comandi del chrome di
|
||||
un portale host nel modello semantico usato da Thoth. L'adapter non possiede autorizzazione,
|
||||
sessioni di workflow o contenuti del modello.
|
||||
|
||||
**Host Shell State** — Il minimo stato visuale fornito dal portale host: locale UI, tema e stato
|
||||
fullscreen. In una Embedded Thoth Shell è la fonte autorevole per queste preferenze;
|
||||
non include identità, token o stato di autenticazione, che restano responsabilità dell'accesso.
|
||||
|
||||
**UI locale** — La lingua delle label, dei messaggi, dei tooltip, degli stati e delle istruzioni
|
||||
non generate dal modello nell'interfaccia Thoth. È distinta dalla lingua dei contenuti di un
|
||||
workspace.
|
||||
|
||||
**Interaction language** — La lingua in cui il modello presenta domande, spiegazioni e proposte
|
||||
al revisore durante una sessione. Viene fissata alla creazione della sessione e rimane invariata
|
||||
durante una ripresa, anche se la UI locale corrente cambia.
|
||||
|
||||
**Administrative Page Family** — L'insieme delle cinque Administration Page che condividono shell,
|
||||
navigazione, tipografia e regole responsive, pur mantenendo contenuti e operazioni specifici:
|
||||
Workspace, Evidence, Memory, Database e Pi.
|
||||
|
||||
## Installazione
|
||||
|
||||
**Manual standalone installation** — Una copia di ThothII predisposta per l'uso autonomo da una
|
||||
persona che possiede il computer, con una Full Thoth Shell e servizi applicativi locali. La
|
||||
procedura non implica che DWH o provider LLM siano locali o disponibili offline.
|
||||
|
||||
**Installation bootstrap** — L'insieme delle attività iniziali che rende disponibile una
|
||||
installazione manuale: verifica dell'host, generazione della configurazione, predisposizione
|
||||
delle credenziali protette e avvio dei servizi. Non è un installer dell'applicazione.
|
||||
|
||||
**Platform acceptance** — La verifica che una Manual standalone installation possa essere
|
||||
predisposta e avviata su una specifica combinazione di sistema operativo, architettura e runtime,
|
||||
distinta dalla verifica funzionale del collegamento a DWH e provider LLM.
|
||||
|
||||
@@ -160,6 +160,15 @@ users can scan structure without adding nested containers.
|
||||
|
||||
## Colors
|
||||
|
||||
The full-mode application header matches Omics Portal's `--gsd-red-primary`
|
||||
(`#CB333B`) in both themes. Its complete wordmark, including `II`, and controls
|
||||
use a near-white foreground. This header is absent in embedded mode. The sidebar
|
||||
and welcome wordmarks retain their red suffix. Context editing places workspace,
|
||||
model and Done in one desktop row, stacking on narrow containers. Session-scope
|
||||
tabs retain their selected fill and accessible keyboard state with a uniform one-pixel
|
||||
border on every side, gray when inactive and red when active. Their padding is 11px
|
||||
horizontal and 3px vertical, with a 38px minimum height and wrapping labels.
|
||||
|
||||
The palette combines warm porcelain surfaces, warm graphite text, and an instrument red used only
|
||||
for action, focus, and important state. OKLCH values in the frontmatter are normative because the
|
||||
frontend uses OKLCH tokens directly.
|
||||
@@ -299,6 +308,27 @@ default, hover, focus, active, disabled, loading, and error behavior where those
|
||||
|
||||
### Navigation
|
||||
|
||||
- **Workspace readiness:** the Workspace navigation button carries an 8px dot to
|
||||
the right of its label. Green means a selected workspace with confirmed ready
|
||||
preprocessing and no query error; all other states are red. The button's
|
||||
tooltip and accessible description retain the translated exact state. Do not
|
||||
add a separate readiness text row or change the backend readiness gate.
|
||||
- **Session groups:** one accessible single-open accordion contains Active sessions
|
||||
and Archive, both initially closed. Below the scope tabs, show only their
|
||||
adjacent section headers, without a redundant Sessions heading. Selection and
|
||||
bulk-delete controls belong inside each panel and only appear for nonempty
|
||||
lists. Select all affects that list only, preserves the other list's selection,
|
||||
and exposes a mixed state for partial selection. Preserve the existing archived
|
||||
flag as the grouping rule, independent of whether a Pi process is running.
|
||||
Opening a section closes the other; either can be collapsed, including both.
|
||||
Empty lists show only the translated "No sessions yet." message.
|
||||
The open section uses the rail's remaining height; its list scrolls internally
|
||||
with a cap of `min(18rem, 35dvh)`, while its trigger remains outside that scroll
|
||||
area. The mobile navigation dialog supplies a bounded viewport-height container.
|
||||
Keyboard users can focus and scroll each labelled panel.
|
||||
- **Session entry:** one Session button returns to the current unfinished session,
|
||||
including provisional creation, without resetting or reconnecting it. Otherwise
|
||||
it prepares a new question using the normal readiness and unsaved-work guards.
|
||||
- **Style:** compact session rows use `8px` corners and restrained vertical padding.
|
||||
- **Default / Hover / Active:** porcelain at rest, Sunken Surface on hover, and a muted Navigation
|
||||
Active red with a defined border when current. Exactly one top-level navigation control is current.
|
||||
@@ -311,13 +341,31 @@ default, hover, focus, active, disabled, loading, and error behavior where those
|
||||
width; a Navigation button opens the shared accessible dialog. Selecting another archive
|
||||
page or pressing Escape closes it. Desktop retains the right session sidebar and its My sessions /
|
||||
All sessions tabs. Core retains question/answer, eight phases, reviewer gates and the left log.
|
||||
The portal owns the red header and left sidebar; ThothII must not duplicate them. Size to the
|
||||
In embedded mode the portal owns the red header and left sidebar; ThothII must not duplicate them. Size to the
|
||||
actual application container. Narrow session document panels may use the available width.
|
||||
|
||||
### Session review and confirmations
|
||||
|
||||
Session dialogs use the visible application area, including the portal's header
|
||||
and side rail. Artifact and schema-column review can grow to 80rem wide and the
|
||||
available height; short confirmations use up to 40rem and at least 18rem when
|
||||
space permits. Keep a 24px outer margin on desktop and 8px on small or short
|
||||
screens. Long review content scrolls internally; on very short screens the
|
||||
whole dialog can also scroll so every action remains reachable.
|
||||
|
||||
Session forms and review gates repeat their existing primary confirmation above
|
||||
and below the content, sharing selection, validation, pending state and response
|
||||
handlers. Alternate-response inputs follow the same rule. Reserved navigation
|
||||
controls remain below the review. Stop/delete initially focus Cancel; rename
|
||||
initially focuses the name field. Administration dialogs and forms retain their
|
||||
existing layout and actions.
|
||||
|
||||
### Tabs
|
||||
|
||||
- **Shape:** compact label tabs sit on a shared baseline with rounded top corners and a two-pixel
|
||||
lower edge. Inactive labels retain a complete Quiet Border and Porcelain Card surface, so every
|
||||
lower edge, except session-scope tabs which use a uniform one-pixel border, rounded
|
||||
corners and a 4px gap without a shared border or negative bottom margin.
|
||||
Inactive labels retain a Quiet Border and Porcelain Card surface, so every
|
||||
label reads as a tab before interaction; hover feedback reinforces clickability.
|
||||
- **Current:** the selected tab uses the muted Navigation Active red for its fill, text, and defined border.
|
||||
It must expose `aria-selected`, participate in a labelled `tablist`/`tabpanel`, and be the only
|
||||
@@ -337,6 +385,38 @@ default, hover, focus, active, disabled, loading, and error behavior where those
|
||||
|
||||
### Curated Evidence Documents
|
||||
|
||||
Memory and Evidence share the `thot-knowledge-reader` reading contract. Use locally
|
||||
bundled Manrope with normal tracking for prose and labels, and these fixed roles:
|
||||
|
||||
- Card title: 24px, weight 600, line-height 1.3 (`thot-knowledge-title`).
|
||||
- Field/section heading, including Scope and Provenance: 20px, weight 600,
|
||||
line-height 1.4, 8px clearance below (`thot-knowledge-heading`).
|
||||
- All narrative text, including scope, lists and provenance: 16px, weight 400,
|
||||
line-height 1.65. Do not apply compact UI text sizes to these fields.
|
||||
- Authored Markdown subheadings inside a field: 16px, weight 600, line-height 1.5,
|
||||
24px above/8px below. They remain subordinate to the enclosing field heading;
|
||||
their semantic heading levels and original content are preserved.
|
||||
- Technical metadata labels/values: 14px/1.5, with weight 600 for labels.
|
||||
Only code, paths and machine identifiers use the technical monospace family at
|
||||
14px/1.65, identical for inline and fenced code (never compound `em` shrinkage).
|
||||
|
||||
Separate reading sections by 24px; keep the first Markdown block flush with its
|
||||
field heading's 8px bottom gap. The same typography applies in light/dark and at
|
||||
all responsive widths. Controls and archive indexes retain their compact UI roles.
|
||||
|
||||
Memory and Evidence detail readers use the entire available content width, without
|
||||
the ordinary 72–75ch prose cap. This is the owner's explicit reading-layout choice.
|
||||
Long unstructured paragraphs are split for display at existing sentence/semicolon
|
||||
boundaries outside inline code and links; authored Markdown structure and stored
|
||||
content are unchanged. Paragraph spacing is 1.25em. Scope and provenance share the
|
||||
available width; provenance excerpts render Markdown rather than literal markers.
|
||||
Copy actions use the two-overlapping-sheets icon, an accessible name/tooltip and
|
||||
live success/failure feedback instead of a visible Copy label.
|
||||
|
||||
Memory has four explicitly FAKE formatting examples, one per family, in a separate
|
||||
expandable section. They reuse the real detail reader but never enter persistence,
|
||||
indexing, link search or model recall, and expose no edit/delete/save actions.
|
||||
|
||||
Curated evidence follows a fixed reading order: title, compact type and purpose summary, scope,
|
||||
typed content, supporting excerpts, review items, then technical provenance. Curated v4 files
|
||||
use short, visible YAML frontmatter for identity and classification. The Markdown title and
|
||||
@@ -362,7 +442,8 @@ paths with copy controls, never browser file links to container-only locations.
|
||||
- **Do** preserve information density with headings, rhythm, and progressive disclosure.
|
||||
- **Do** keep keyboard focus explicit and pair color with text, shape, icon, or position.
|
||||
- **Do** respect `prefers-reduced-motion` while preserving immediate non-kinetic feedback.
|
||||
- **Do** use English for interface chrome and the workspace language for persisted document content.
|
||||
- **Do** use the selected interface language (English by default) for chrome and preserve the
|
||||
workspace language for persisted domain content. Session interaction language remains pinned.
|
||||
- **Do** render curated metadata and scope as Markdown prose or lists, never as a frontmatter table.
|
||||
- **Do** break long curated rules into paragraphs, labelled subsections, and lists at existing
|
||||
punctuation boundaries while preserving the exact canonical text for machines.
|
||||
|
||||
@@ -1,536 +1,95 @@
|
||||
# ThothII — Project State
|
||||
|
||||
Last updated: 2026-09-12.
|
||||
|
||||
This file is the short operational snapshot. Stable commands and the architecture mental model
|
||||
live in `AGENTS.md`; current design and runtime contracts live under `docs/architecture/`,
|
||||
`docs/contracts/`, `docs/adr/`, and `docs/evidence.md`. Superseded plans and reports are
|
||||
available from Git history rather than duplicated in the working tree.
|
||||
|
||||
The guarded server migration from a legacy checkout to the schema-v2 installation, Gitea source,
|
||||
Authentik, internal catalog/embedding services, and the PSD workspace repository is documented in
|
||||
`docs/operations/server-upgrade-gitea-workspace-v2.md`. Treat its operator gates and rollback
|
||||
requirements as mandatory; do not replace the running server stack in place.
|
||||
|
||||
## Current product shape
|
||||
|
||||
### Isolated visual review, awaiting owner acceptance
|
||||
|
||||
The UI revision is isolated in `/Users/mp/projects/ThothII-visual-review`, branch
|
||||
`codex/ui-visual-review`, based on `2d1b714e`. The original checkout and its prototypes
|
||||
remain intact. No merge to `main` has been performed.
|
||||
|
||||
Local Docker at `http://127.0.0.1:8080/` now runs the frontend image
|
||||
`thothii-frontend:visual-review-20260912`. Only frontend was recreated; Core and all
|
||||
data services/volumes/configurations are unchanged. The prior look is preserved as
|
||||
`thothii-frontend:before-visual-review-20260912`. All five running services are healthy.
|
||||
|
||||
The revision uses bundled Manrope throughout, shared type roles, restrained semantic
|
||||
colors, clearer Admin copy and a readable compact session-document panel. Core and
|
||||
session behavior remain covered by the existing regression suite. Verification:
|
||||
679 frontend tests, 7 Playwright visual/interaction scenarios and a production build.
|
||||
See `docs/reports/2026-09-12-ui-visual-review-delivery.md` for scope, limits and the
|
||||
exact local rollback command. Visual approval is required before adoption on `main`.
|
||||
|
||||
Gitea #28–#31 follow-up is implemented in this checkout: Workspace's four tabs,
|
||||
Database list-first entry without the preparation footer, full-height Pi instructions
|
||||
with installation-host OS selection, and short Admin navigation labels. Core and
|
||||
session behavior are retained. At the owner's request, these changes were rebuilt into
|
||||
local Docker on 2026-09-12 at 18:31 UTC. Core/frontend are healthy and the UI at
|
||||
`http://127.0.0.1:8080` serves the updated bundle. The host projection now supplies
|
||||
`THT_HOST_PLATFORM=darwin`, so Pi selects macOS rather than the container's Linux OS.
|
||||
Persistent dependency containers and volumes were unchanged. Rollback images are tagged
|
||||
`thothii-core:before-admin-28-31-20260912` and
|
||||
`thothii-frontend:before-admin-28-31-20260912`. See
|
||||
`docs/reports/2026-09-12-admin-issues-28-31.md` for verification and deployment details.
|
||||
|
||||
The latest context-shelf A and five Administration pages are implemented locally.
|
||||
At the owner's request, local Docker project `thothii-18998cca7b0a` was rebuilt and
|
||||
its core/frontend recreated on 2026-09-12. The real UI at `http://127.0.0.1:8080`
|
||||
serves shelf A; both services and their existing dependencies are healthy.
|
||||
Runtime model projections were regenerated as schema v2 with the single
|
||||
`zai/glm-5.3` interaction default. Persistent services/volumes were not recreated.
|
||||
The local launcher `/private/tmp/thothii-memory-preview.sh` now adds
|
||||
`/private/tmp/thothii-context-a.compose.yaml` last, building from this checkout
|
||||
instead of the earlier Memory worktree. Previous images are retained under
|
||||
`thothii-core:before-context-a-20260912` and
|
||||
`thothii-frontend:before-context-a-20260912`. Remote server deployment remains pending.
|
||||
Core/session behavior is retained; one independently remembered workspace/model
|
||||
pair controls both Core and Admin. Unsaved Admin changes block navigation and
|
||||
context changes; operation activity locks the selectors. See
|
||||
`docs/reports/2026-09-12-context-shelf-a-implementation.md` for verification and the
|
||||
remaining server/Omics integration gate. Prototype alternatives remain untouched.
|
||||
|
||||
ThothII is a human-in-the-loop datamart builder with three independently built layers:
|
||||
|
||||
```text
|
||||
frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness → DWH (read-only)
|
||||
```
|
||||
|
||||
The harness owns the deterministic eight-phase NL→SQL workflow and all session persistence.
|
||||
The backend remains a process/RPC/SSE bridge for sessions and now also owns an isolated PostgreSQL
|
||||
metadata catalog for administrative database configuration. The frontend renders the review gates
|
||||
and keeps the live transcript in memory. See
|
||||
`docs/architecture/components.md` for the detailed component and data-flow map.
|
||||
|
||||
## Memory M1–M3, Evidence E1–E3 and joint workflow repair X1 implemented
|
||||
|
||||
Browser authorization now derives permissions from validated session roles using the current
|
||||
catalog. This fixes Memory/Evidence navigation remaining disabled for administrators whose
|
||||
remembered login predates those permissions; refreshing the page loads the updated permissions.
|
||||
|
||||
The owner requested two independent administration projects: Memory management and Evidence
|
||||
management. Their navigation entries must sit immediately after Database management, as peers;
|
||||
neither page belongs to Database management. Both require complete browsing, filtering, and CRUD
|
||||
without an active core session. Shared requirements and the two project briefs are linked from
|
||||
`docs/plans/2026-09-08-memory-evidence-administration.md`. Memory administration is implemented;
|
||||
Evidence administration is implemented through external file editing and explicit consolidation.
|
||||
Evidence editing requires an explicit evolution of the current authoring/publication contract.
|
||||
The M1 specification is at `docs/plans/2026-09-08-memory-m1-spec.md` and published as
|
||||
[M1 — Archivio autorevole e amministrazione delle Memory Card](https://git.tylconsulting.it/mptyl/ThothII/issues/27)
|
||||
with the `ready-for-agent` and `enhancement` labels.
|
||||
It covers the authoritative store, administrative CRUD, projection recovery, and current
|
||||
Memory/exemplar producer integration. Its accepted test boundaries are the public harness
|
||||
service, Fastify APIs, and the AppShell page, joined by a focused real-stack browser path.
|
||||
The owner confirmed those boundaries and authorized publication on 2026-09-08.
|
||||
M1 is implemented locally: PostgreSQL authority in `thoth_memory`, versioned installation
|
||||
migrations, admin CRUD for all four families, structured dependencies and links, explicit
|
||||
projection recovery, verified recall and current workflow producers. The page requires no
|
||||
active session or DWH binding. The existing `catalog-migrate` preparation service now runs
|
||||
Memory migrations as well. Existing installations need that preparation before using M1;
|
||||
the initial implementation did not deploy or migrate the owner's stacks.
|
||||
The integrated browser check passed with real authentication, Fastify, ThtRunner, harness,
|
||||
PostgreSQL and Qdrant; embeddings were deterministic and unrelated Pi/session activity used
|
||||
test fixtures. See `docs/plans/2026-09-08-memory-m1-validation.md` for results and commands.
|
||||
M2 is implemented locally: Memory dense/BM25 fusion, physical and business scope filters,
|
||||
bounded outgoing-link expansion and joint ranking, all resolved against current PostgreSQL
|
||||
authority. Migration `002_hybrid_projection.sql` makes old dense projections pending until
|
||||
explicit retry/rebuild; Reference remains separate. The real retrieval check uses the configured
|
||||
`qwen3-embedding:0.6b` model, a separate Ollama process with a read-only model-volume mount,
|
||||
and isolated PostgreSQL/Qdrant resources. See `docs/plans/2026-09-09-memory-m2-validation.md`.
|
||||
M3 is implemented: editable F8 summary grounded in effective approved decisions, explicit
|
||||
updates with concurrent-edit protection, selected-card/link transactions and durable review
|
||||
receipts. Finalization no longer saves exemplars implicitly. SQL rules and explained errors
|
||||
are consulted in the existing F4/F6/F7 gates. Successful Catalog physical synchronization
|
||||
performs dependency cleanup, preserving the original removals for recovery across restarts.
|
||||
Migration `003_review_receipts.sql` is required. Validation includes a real GLM 5.3 generation
|
||||
case against synthetic PostgreSQL data; see `docs/plans/2026-09-09-memory-m3-validation.md`.
|
||||
Evidence administration and the joint X1 conflict-repair increment are now implemented.
|
||||
The same local preview was subsequently rebuilt with M3 and migration 003 applied.
|
||||
Core and frontend now include the final Memory review and physical dependency cleanup.
|
||||
On 2026-09-09, at the owner's request, the local PSD Docker installation
|
||||
`thothii-18998cca7b0a` was updated from this worktree. Core/frontend images were rebuilt,
|
||||
Catalog and Memory migrations completed, and all five services became healthy. The UI is at
|
||||
`http://127.0.0.1:8080`, using the existing local authentication and persistent volumes.
|
||||
The `psd-clinical` authoritative Memory archive is initially empty (no legacy import).
|
||||
The existing installation configuration remains in `/Users/mp/projects/ThothII/deploy/psd/`;
|
||||
`/private/tmp/thothii-memory-preview.sh` invokes its Compose files with a final build-context
|
||||
and migration-command override from this worktree. A future build from the main checkout
|
||||
will use that checkout's code, so retain the worktree override until the changes are integrated.
|
||||
Memory revision history and compatibility with existing development sessions are not requirements.
|
||||
The agreed Memory scope includes reusable domain clarifications, SQL construction rules, solved
|
||||
questions, and explained, approved mistakes to avoid. This extends the current runtime's
|
||||
`concept_clarified`-only reusable Memory contract. The owner also approved an editable final summary
|
||||
for proposed additions/updates and Memory consumption in the relevant existing review gates.
|
||||
Further agreed behavior includes persistent corrections for Memory/Evidence conflicts through
|
||||
explicit choices, deletion of Memory with invalid dependencies after successful physical schema
|
||||
synchronization, and bounded functional/regression tests instead of a general quality benchmark.
|
||||
In-house Memory evolution is approved, including hybrid Qdrant retrieval and explicit card links
|
||||
traversed in core, without a dedicated graph database. Both capabilities belong to the current
|
||||
scope. PostgreSQL is the agreed authority for Memory Cards, links, and schema dependencies;
|
||||
Qdrant is a rebuildable index. Links are reviewed with cards and editable in Administration;
|
||||
deleting a card removes its incident links while preserving the other cards. The accepted,
|
||||
implemented architecture is recorded in
|
||||
`docs/adr/0018-use-postgres-for-memory-and-qdrant-for-retrieval.md`.
|
||||
For Evidence administration, Q12 rejects a separate editorial publication workflow.
|
||||
The final R0 direction uses external editors and a manual consolidation command that
|
||||
validates structure, reports required corrections, updates derived metadata, and
|
||||
activates the local Evidence index. The operator then checks the diff and runs Git
|
||||
commit/push manually. No watcher, automated Git, or web editor is required.
|
||||
The owner's later simplification
|
||||
instruction removes the requirement to support administrative edits while core work
|
||||
is in progress. Deliberate corrections made by the workflow itself remain supported.
|
||||
The context specialist writes Evidence drafts independently of the installation and
|
||||
without PostgreSQL access; the system refines them and stores them locally for use
|
||||
and maintenance. The revised Q11 recommendation separates external drafts from a
|
||||
durable local canonical file archive, removing automatic commit/push from CRUD.
|
||||
The owner has now accepted local files and requires discoverable, editable Markdown
|
||||
for nontechnical domain specialists, with no JSONL management surface. Editors on
|
||||
Mac/PC or vim/nano on the server are the chosen R0 editing surface. Evidence
|
||||
management keeps browsing/filtering/detail and clearly identifies the persistent
|
||||
working tree, each Markdown file's actual host path, and the manual commands.
|
||||
E1 implements editable Curated Evidence v4, deterministic legacy conversion, persistent
|
||||
local files and a consolidation API with immutable candidates, manual provenance,
|
||||
deletion records and recoverable activation. E2 connects its installed command, runtime source
|
||||
selection and administration page. The operator completes Git steps manually.
|
||||
All 35 PSD units were converted on an isolated copy with identical IDs and typed content.
|
||||
Tests exercise visible edits through normalization, indexing and recall with real Qdrant;
|
||||
see `docs/plans/2026-09-09-evidence-e1-validation.md` and
|
||||
`docs/contracts/curated-evidence-v4.md`. E2 is now running on the local Docker preview:
|
||||
all 35 PSD units were converted and indexed through the installed command. The editable
|
||||
host archive is `/Users/mp/projects/ThothII/deploy/psd/evidence-registry/repo/psd-clinical/evidence`.
|
||||
The original registry-volume checkout and original author repository were retained.
|
||||
The installation descriptor now includes `workspace-bindings.yaml` and `evidence-host.yaml`
|
||||
so native maintenance uses the same volumes and checkout as the preview. Descriptor backup:
|
||||
`/private/tmp/thothii-installation-before-e2.yaml`; previous native binary: `/private/tmp/tht-before-e2`.
|
||||
The launcher remains `bash /private/tmp/thothii-memory-preview.sh`; its worktree build override
|
||||
is still required until integration. Runtime lease filenames now include rendered bytes so
|
||||
upgrading the Evidence renderer does not collide with old immutable configs; Catalog
|
||||
input fingerprints and readiness are unchanged. See `docs/plans/2026-09-09-evidence-e2-validation.md`.
|
||||
E3 adds explicit source acquisition/refinement and durable comparisons in Evidence management.
|
||||
Local drafts go in `evidence/incoming/`; original local documents and configured HTTP/S3
|
||||
sources are reacquired only by **Import or refresh sources** or installed
|
||||
`tht workspace evidence refresh --workspace <id>`. Keep/replace decisions, including the
|
||||
native `workspace evidence decide` command, activate through the existing archive/index
|
||||
path and have durable retry state. Acquired source versions and remote provenance stay
|
||||
local; old documentary lineage can coexist with current manual declarations.
|
||||
The installed preview's 35 PSD sources were verified unchanged with no new proposals.
|
||||
The previous native CLI is backed up at `/private/tmp/tht-before-e3`.
|
||||
See `docs/plans/2026-09-09-evidence-e3-validation.md` for tests and validation limits.
|
||||
X1 adds `reviewer_archive_repair`: closed alternatives with complete before/after content,
|
||||
explicit rejection/reformulation, admin-only application, durable session receipts and
|
||||
retry of saved but inactive corrections. The coordinator uses the canonical Memory and
|
||||
Evidence services; phase approval remains separate. Migration `004_archive_repairs.sql`
|
||||
is required. See `docs/contracts/archive-repair.md` for authorization and recovery limits.
|
||||
X1 validation is recorded in `docs/plans/2026-09-09-archive-repair-x1-validation.md`:
|
||||
both archives were corrected and retrieved through the actual CLI with real PostgreSQL
|
||||
and Qdrant; desktop/mobile widget behavior and permission failures were verified separately.
|
||||
The local preview images include X1 and migration 004 is applied. Follow-up technical
|
||||
acceptance passed with configured GLM 5.3 generating closed conflict alternatives and
|
||||
the chosen Memory correction persisted and retrieved. An authenticated browser test
|
||||
also verified both administration pages, navigation order, Evidence filtering, workspace
|
||||
404s, desktop/mobile layout, and Evidence survival after Memory deletion. All approved
|
||||
technical increments/checks are complete. A real PSD domain-conflict session remains
|
||||
the reviewer's semantic acceptance check; automated cases did not modify PSD knowledge.
|
||||
The joint browser inspection also fixed mobile archive navigation: below 768px,
|
||||
Memory and Evidence keep the full content width and open navigation in the shared
|
||||
accessible dialog. Desktop retains its sidebar; the local frontend image includes this fix.
|
||||
The owner accepted the remaining simplifications and requested explicit clarification
|
||||
of the core format change and the simple terminal-based Git check. E1 must adapt
|
||||
the Evidence parser, renderer, authoring, validation, and normalization; convert
|
||||
existing files and reindex; and verify that visible edits reach core consumption.
|
||||
Preserve the internal typed model where possible. This precedes the administrative
|
||||
page and is not merely a presentation change. Human inspection uses normal Git
|
||||
status and optional line-level diff commands; no custom diff viewer or mandatory
|
||||
double review is required.
|
||||
The suggestion of making PostgreSQL the Evidence authority was withdrawn after this
|
||||
clarification; it was never implemented or accepted as a replacement for Q11.
|
||||
Q13 keeps manual corrections active when updated sources contradict them, until an
|
||||
administrator resolves the comparison; deleted Evidence must not be regenerated
|
||||
automatically. Q14 allows direct manual creation and records a manual declaration
|
||||
as the current source, preserving any original document as distinct provenance.
|
||||
Q15 refreshes external sources only on explicit administrator request; normal saves
|
||||
and lookups do not reacquire them. These decisions, now implemented through E1–E3, are recorded in
|
||||
`docs/adr/0019-author-evidence-in-app-with-automatic-activation.md`.
|
||||
The decision-by-decision review is recorded in
|
||||
`docs/plans/2026-09-08-memory-evidence-simplification-review.md`; it distinguishes the
|
||||
new constraints from the revised technical recommendations. It also specifies a
|
||||
sequential save with minimal durable retry state and direct Memory cleanup after
|
||||
successful schema synchronization, without new queues or event infrastructure.
|
||||
The delivery order remains Memory, Evidence, and persistent conflict repair between
|
||||
both modules. Local curated Evidence must survive preprocessing Clear and be backed
|
||||
up as primary data; the Qdrant projection remains rebuildable.
|
||||
No runtime gate change or administrative page is implemented yet.
|
||||
|
||||
## Evidence restructuring — accepted
|
||||
|
||||
The evidence restructuring and PSD migration completed real acceptance on 2026-08-25.
|
||||
|
||||
- The curated PSD revision contains 35 approved Evidence units and 60 review items.
|
||||
- The PSD authoring repository publishes all 35 units using Curated unit schema v3. Its table-free
|
||||
presentation uses hidden canonical metadata, wrapping Markdown scope lists, list-based enum
|
||||
values, and collapsed technical provenance. Long domain rules now have a deterministic
|
||||
human-readable presentation while retaining their exact canonical text for vector ingestion.
|
||||
`tht evidence migrate <workspace-root>` performs the deterministic v1/v2 upgrade and older-v3
|
||||
presentation rewrite without model calls. The structured-rule PSD rewrite is currently local and
|
||||
pending commit/publication.
|
||||
- The accepted snapshot is
|
||||
`psd-clinical-675990d90eae51da6f2bd51b1ae2609f245772ef-snapshot`.
|
||||
- The active generation is `gen:f968b3bd7a553dbfef3cf47093698f2bc7f95f11`.
|
||||
- Retrieval acceptance reached 20/20 Hit@10.
|
||||
- A real session, `20301df7-cad7-403d-a4c1-9f35c9d07b66`, completed F1–F8 with five
|
||||
receipts, three CTEs, and a final result of 78 patients.
|
||||
- The durable acceptance record is
|
||||
`docs/testing/evidence/evidence-restructuring-psd-acceptance-2026-08-25.md`.
|
||||
|
||||
The canonical authoring, validation, publication, materialization, and preprocessing flow is
|
||||
documented in `docs/evidence.md`. The governing contracts are
|
||||
`docs/contracts/workspace-evidence-v3.md` and
|
||||
`docs/contracts/workspace-preprocessing-cli.md`.
|
||||
The incremental server procedure for the `260906-preprocessing-complete` release is
|
||||
`docs/operations/server-handoff-260906-preprocessing-complete.md`.
|
||||
|
||||
## Workspace preprocessing and configuration
|
||||
|
||||
The native host CLI `tht` is the operator surface. Workspace preprocessing runs through:
|
||||
|
||||
```sh
|
||||
tht --installation /absolute/path/thothii-installation.yaml \
|
||||
workspace preprocess run --workspace <workspace-id>
|
||||
```
|
||||
|
||||
This complete one-shot command uses the profile-gated `workspace-maintenance` service. Partial DWH,
|
||||
schema, Evidence, and vector mutation commands are retired.
|
||||
|
||||
The right Administration sidebar invokes that same operation for the selected workspace. It shows
|
||||
only current readiness or the latest bounded failure diagnostic; there is no preprocessing history.
|
||||
Known non-ready state disables **New session**, while backend admission remains authoritative.
|
||||
The same control exposes an inline-confirmed **Clear** action to remove replaceable reference
|
||||
vectors, LSH, corpus, and checkpoints while preserving the separate Memory collection. The host CLI
|
||||
equivalent is `workspace preprocess clear`.
|
||||
|
||||
Each workspace now uses `<workspace>-reference` for Schema, relationships, and Evidence and
|
||||
`<workspace>-memory` for `memory` and `solved_question`. Clear and preprocessing own only the former.
|
||||
LSH ownership additionally binds the Catalog database ID and Metadata Content Revision, so derived
|
||||
values cannot be reused across database identities or Catalog revisions.
|
||||
|
||||
Workspace descriptors use schema v4 and contain only workspace identity and optional Evidence.
|
||||
PostgreSQL Metadata Catalog owns database identity, binding, schema, descriptions, sensitivity, and
|
||||
relationships; model, provider, embedding, and vector-store configuration is installation-owned. For
|
||||
PSD, workspace content and runtime roots point to the
|
||||
separate uncommitted repository `/Users/mp/projects/tht-workspace-psd`. Secrets remain outside
|
||||
Git and are supplied only through installation-local protected files.
|
||||
|
||||
## Installation Model Catalog
|
||||
|
||||
`thothii-installation.yaml` schema version 2 is the only operator-authored source for session,
|
||||
metadata-generation, and embedding models. The host `tht` lifecycle validates `modelCatalog` and
|
||||
regenerates the backend catalog, Pi `models.json`/`settings.json`, and Compose override under the
|
||||
installation-local `generated/` directory. Those projections are replaceable runtime adapters:
|
||||
they are not edited, backed up, or treated as configuration.
|
||||
|
||||
Core and Administration now share one canonical `modelCatalog.defaults.interaction` per installation,
|
||||
independent of workspace. Runtime catalog schema v2 contains only `defaultInteraction`; apply the host,
|
||||
backend, and regenerated projections together. Equal legacy defaults normalize on read; conflicting
|
||||
ones require an explicit operator choice. With Admin AI configured, selectable models are the
|
||||
intersection of the Pi and LiteLLM adapters; Core-only installations remain supported without Admin AI.
|
||||
The existing Core and Database controls share the operational selection. Explicit model choices are
|
||||
remembered per authenticated user/application mount in this browser, not in installation settings.
|
||||
Resume uses that selection/default while preserving the historical workspace/revision and manifest.
|
||||
Every model must be manually exercised in both Core and Admin as documented in
|
||||
`docs/general/pi-configuration.md`; validation is not a live model certification.
|
||||
These changes and shelf A are now deployed to local Docker; remote deployment remains pending.
|
||||
|
||||
PSD DeepSeek Pro/Flash now share canonical `deepseek/...` identities across native Pi and LiteLLM,
|
||||
using the existing `DEEPSEEK_API_KEY` bundle entry. Its value was confirmed identical to the working
|
||||
Pi key without exposing it; no secret files were changed. The duplicate `deepseek-metadata` descriptor
|
||||
is removed locally and the tracked example uses the shared provider. `secret_env` overrides legacy
|
||||
Pi auth only inside temporary runtime snapshots and fails closed if the bundle key is missing.
|
||||
The original auth store/history and `zai/glm-5.3` default are preserved. Local Docker projections
|
||||
and core/frontend were updated together on 2026-09-12. Regenerate projections with
|
||||
the matching release for the separate server deployment.
|
||||
|
||||
Provider authentication declares
|
||||
one explicit mode (`secret_env`, `pi_auth`, or `none`); `secret_env` names a protected bundle key.
|
||||
The backend settings store now owns only the selected workspace and thinking level. Existing v1
|
||||
installations use the explicit catalog migration command; schema-v3 workspace descriptors are
|
||||
converted deterministically in their curator-owned repository before commit. Strict runtime loading
|
||||
does not silently infer or merge legacy sources. ADR 0013 and
|
||||
`docs/plans/2026-09-02-installation-model-catalog.md` record the decision and implementation.
|
||||
|
||||
## Database management
|
||||
|
||||
The database, table, and authoritative physical-schema catalog slices are implemented. Database
|
||||
Management now opens the Fleet Ledger presentation by default inside `AppShell`, lists every YAML
|
||||
workspace, creates at most one PostgreSQL database configuration per workspace, edits direct
|
||||
PostgreSQL, REST API, or SSH-tunnel installation bindings, replaces write-only encrypted secrets,
|
||||
and tests supported connector bindings. The surface keeps one responsive AG Grid visible at a time:
|
||||
databases lead to tables, tables lead to columns, and relationships are a sibling database view.
|
||||
Parent navigation remains explicit through the breadcrumb and emphasized back control.
|
||||
|
||||
Selection-scoped operations use one action selector plus an explicit **Run** control; ineligible
|
||||
actions remain visible with their disabled reason, while row-scoped actions stay in the pinned final
|
||||
column. The KPI strip reads installation-wide or selected-database aggregates from
|
||||
`GET /catalog/metrics`. Database configuration, metadata editors, synchronization history,
|
||||
description history, and sensitive-field review/history use the production APIs in right-side
|
||||
drawers rather than prototype fixtures; closing a history drawer does not stop its background run.
|
||||
|
||||
Sensitive-field review is now driven by the versioned local `sensitivity-v4` policy, not by a
|
||||
catalog model. The backend reads selected source tables through read-only, database-specific
|
||||
adapters and makes every `sensitive | non_sensitive` draft decision in the TypeScript
|
||||
`SensitivityClassifier`. A single validated match protects the column. Tables up to 1,000 rows are
|
||||
fully scanned; larger tables use breadth-first 300, 1,000, and text-only 3,000-value targets, with a
|
||||
five-second limit per source query and no global request deadline. Source failures fail the run
|
||||
instead of yielding `unknown`; coverage remains visible separately from the proposal. Draft
|
||||
assessments remain transient until an administrator explicitly saves them. Optional GLiNER2
|
||||
evidence is CPU-only, offline, opt-in, and never replaces the deterministic decision point; see
|
||||
`docs/operations/sensitivity-analysis.md`. The earlier v1 PSD shadow comparison kept NER disabled by
|
||||
default; see `docs/reports/2026-09-02-psd-sensitivity-shadow.md`. The v2 comparison completed all
|
||||
2,275 columns: CPU NER added 18 sensitive proposals and increased warm runtime from 50.1 to 61.3
|
||||
seconds; see `docs/reports/2026-09-03-psd-progressive-sensitivity-shadow.md`.
|
||||
Version 4 excludes declared `bigint` primary-key columns and conventionally named `pk bigint`
|
||||
columns before source inspection, reporting both as non-informative structural identifiers while
|
||||
distinguishing declared constraints from inferred roles.
|
||||
|
||||
Physical membership, source
|
||||
comments, column types/default/nullability/PK positions, and constraint-level ordered FK pairs are
|
||||
projections of the external schema. They cannot be created, renamed, or structurally edited by
|
||||
hand, but administrators can explicitly clear catalog tables, columns, or relationships without
|
||||
touching the source database, binding, configuration, or secrets. Table deletion cascades through
|
||||
columns and relationships; table-scoped relationship cleanup includes incoming and outgoing
|
||||
relationships. Curated and generated descriptions are editable; generated descriptions start null
|
||||
and Database Management can generate or consolidate them for selected tables, selected columns,
|
||||
all targets, or only targets whose Generated Description is missing.
|
||||
|
||||
Relationship Management is now reachable directly from each configured Fleet database. One
|
||||
Relationship Map shows read-only Physical Relationships together with Generated and Manual Logical
|
||||
Relationships, with Active, Excluded, and All filters. Administrators can add a single-column
|
||||
relationship, run deterministic name/PK/type inference, exclude or restore a logical relationship,
|
||||
or delete it permanently. Exclusion retains a tombstone that a rebuild cannot reactivate; permanent
|
||||
deletion allows a later rebuild to infer the same endpoints again. Inference uses no LLM, embedding,
|
||||
or source values. It supports normalized table-qualified names, unique non-generic PK names,
|
||||
composite-PK source columns, and the `*time_key -> dim_time.<single PK>` warehouse convention while
|
||||
ignoring bare generic names. Explicit table/column metadata cleanup remains a destructive boundary: it removes
|
||||
the attached logical relationships and exclusions and requires a full schema synchronization before
|
||||
inference or runtime publication can continue.
|
||||
|
||||
The previous Database Management renderer remains a temporary comparison fallback for development
|
||||
and staging only: `?db-ui=legacy` is honored in Vite development or when
|
||||
`VITE_DB_MANAGEMENT_LEGACY=true`; it is not a production presentation. The standalone Fleet Ledger
|
||||
prototype on port `5173` also remains temporary until owner acceptance of the integrated surface,
|
||||
after which both migration aids can be removed.
|
||||
|
||||
Schema refresh is one durable asynchronous engine with database-table, selected-table-column,
|
||||
relationship, and full-database actions. Database-level menus expose only the table, relationship,
|
||||
and full scopes; selecting tables exposes column synchronization plus manual column and relationship cleanup for that subset. Database selections
|
||||
also expose manual table and relationship cleanup. Cleanup selections are atomic and share the
|
||||
one-active-operation-per-database exclusion with synchronization. Runs have leases and
|
||||
restart recovery, atomic apply, destructive-diff confirmation with re-scan, cancellation before
|
||||
apply, retained history, and a live SSE log with polling fallback. Null metadata renders blank
|
||||
rather than as a placeholder.
|
||||
|
||||
Direct PostgreSQL and strict known-host-verified OpenSSH use `pg_catalog`. REST bindings use the
|
||||
typed full-snapshot `POST /rpc/schema_snapshot` contract when available. Servers such as the
|
||||
current PSD endpoint that exposes only `POST /rpc/run_query` use one catalog-owned read-only query
|
||||
to return the exact same strict v1 snapshot in a single round trip. Both paths remain fail-closed:
|
||||
an absent capability, query error, partial result, or invalid snapshot applies no catalog changes.
|
||||
SSH is not yet enabled for NL→SQL session runtime.
|
||||
|
||||
The catalog runs in the internal `catalog-db` PostgreSQL service. Kysely migrations are an explicit
|
||||
one-shot `catalog-migrate` operation; `scripts/run-stack.sh` runs it before local startup. Runtime
|
||||
sessions consume an immutable Catalog JSON snapshot tied to the runtime-config lease. It contains
|
||||
the tables, columns, effective descriptions, sensitivity flags, and active relationships used by
|
||||
the harness; PostgreSQL is the exclusive runtime authority for database metadata. Authored
|
||||
workspace YAML remains limited to workspace identity and optional Evidence configuration. The
|
||||
accepted design is recorded in ADR 0016 and the contracts under `docs/contracts/`.
|
||||
|
||||
Semantic aliases, value descriptions, synonyms, and concepts remain deferred to their dedicated
|
||||
slices.
|
||||
|
||||
AI Description Generation uses the catalog's human-owned Sensitive Data Flag. The flag defaults to
|
||||
`false`, including for newly synchronized columns. An administrator may request a local sensitivity
|
||||
analysis for one selected database, selected tables, or selected columns. One deterministic
|
||||
TypeScript classifier combines metadata, bounded source-content rules, and optional CPU-only NER;
|
||||
no generative model decides the result. Its `sensitive` or `non_sensitive` assessments remain an
|
||||
unsaved draft until the human reviews and saves any chosen flag changes, including a downgrade to
|
||||
non-sensitive. Coverage is reported separately; interrupted history may count unprocessed columns.
|
||||
Each started analysis records a separate Sensitivity Analysis Run with aggregate counters and safe
|
||||
ordered events. The progress drawer opens before the synchronous request completes, polls the run,
|
||||
and displays sanitized source-scan and local-NER phase/batch activity while classification is in
|
||||
progress. This operational history never stores per-column assessments, source values,
|
||||
matched spans, prompts, or free-form diagnostics. Saving a sensitive decision persists a sanitized
|
||||
Sensitivity Reason as column Catalog Metadata alongside the human-owned flag; clearing the flag
|
||||
clears that reason. Reloading still discards an unsaved review draft.
|
||||
For unprotected columns, up to five source rows and five representative non-null values may be sent
|
||||
transiently to the configured model provider. Protected columns are omitted from source reads and
|
||||
replaced in the prompt by deterministic plausible values derived only from their metadata. Existing
|
||||
descriptions are not regenerated when a flag changes.
|
||||
|
||||
The accepted AI-description design is recorded in
|
||||
`docs/plans/2026-08-28-ai-catalog-description-generation.md`, with the formal specification in the
|
||||
adjacent `-spec.md` document and Gitea issue #4. Gitea issues #5–#11 deliver the implementation.
|
||||
The runtime deliberately keeps ThothAI's simple operating model: one installation-wide sequential
|
||||
run owned by the backend, one short-lived Python/LiteLLM completion helper per request, and
|
||||
persistence limited to the run, its safe ordered text events, and each Generated Description as
|
||||
soon as it succeeds. The helper performs at most one provider retry and never falls back to another
|
||||
model. Stop terminates the current helper and retains prior results; three consecutive exhausted
|
||||
technical batches fail the run. Startup marks stale queued/running work interrupted, and Unlock is
|
||||
available only when no local start, worker, or helper is live. Runs remain inspectable through a
|
||||
live SSE log with ordered polling fallback; there is no automatic resume or user-facing generation
|
||||
CLI. ADRs 0009–0010 record the runtime and source-sampling decisions.
|
||||
|
||||
The Installation Model Catalog accepts the protected `DEEPSEEK_API_KEY` and `ZAI_API_KEY`
|
||||
references for metadata-generation providers.
|
||||
It also accepts a model with no secret reference only when its OpenAI-compatible endpoint is
|
||||
explicit; this covers the VPN-only AritmoLab Qwen 3.6 server without creating a fake operator
|
||||
credential. The Python client supplies only its fixed non-secret compatibility placeholder.
|
||||
The AritmoLab entry also sets `disableThinking: true`, mapped to the endpoint's chat-template flag,
|
||||
because its default reasoning prose would violate the worker's exact JSON response contract.
|
||||
|
||||
Logical relationship integration with core schema-linking is complete: session creation and resume
|
||||
materialize the active physical/generated/manual map, retrieval-pack generation and Pi receive the
|
||||
same runtime config, and snapshot validation fails closed on a declared missing, invalid, or orphaned
|
||||
endpoint. Broader publication of other Catalog metadata to schema-linking remains a separate future
|
||||
slice.
|
||||
|
||||
**Deferred follow-up — Sensitive Data Policy in schema-linking.** The policy is first delivered
|
||||
and tested in catalog description generation. Its enforcement for core schema-linking remains
|
||||
out of scope until the current tickets are closed and the owner has completed the acceptance test.
|
||||
At that gate, resume the design: `tht` must receive a read-only projection of the current Sensitive
|
||||
Data Flags and exclude values from columns marked sensitive from every LSH result before it is
|
||||
given to Pi. Do not start this integration before the owner gives final approval after that test.
|
||||
|
||||
## Active deployment work and manual gates
|
||||
|
||||
### PSD server deployment program
|
||||
|
||||
The approved design and executable entry point are:
|
||||
|
||||
- `docs/plans/2026-08-20-psd-server-deployment-program-design.md`
|
||||
- `docs/plans/2026-08-20-psd-server-deployment-program.md`
|
||||
- `docs/plans/2026-08-20-psd-server-survey.md`
|
||||
- `docs/plans/2026-08-20-psd-server-project-a-standalone.md`
|
||||
- `docs/plans/2026-08-20-psd-server-project-b-authentik.md`
|
||||
|
||||
Last recorded state:
|
||||
|
||||
- survey: `SURVEY_NO_GO`;
|
||||
- Project A: `BLOCKED_BY_SURVEY_AND_MUTATION_GATE`;
|
||||
- Project B: `BLOCKED_BY_PROJECT_A_AND_PRE_B_GATE`.
|
||||
|
||||
The deployment is a clean replacement: legacy sessions, indexes, and application configuration
|
||||
are not migration inputs. The existing stack remains intact until its documented mutation and
|
||||
rollback gates are explicitly approved. Shared Omics/LocalLLM networks, ETL Evidence, DWH,
|
||||
`dwh-auth`, Supabase, Authentik, Superset, and Aritmolab are outside cleanup scope.
|
||||
|
||||
Human acceptance guides and sanitized report templates live under `docs/testing/` and
|
||||
`docs/testing/evidence/`. The remediation checklist is
|
||||
`docs/operations/psd-server-survey-remediation-checklist.md`.
|
||||
|
||||
### Authentication
|
||||
|
||||
The local/OIDC authentication remediation passed its automated review on 2026-08-18. Release and
|
||||
PSD mutation gates remain governed by:
|
||||
|
||||
- `docs/architecture/authentication.md`;
|
||||
- `docs/plans/2026-08-18-thothii-authentication-acceptance-and-psd-deployment.md`;
|
||||
- `docs/operations/psd-dwh-auth-rollout.md`;
|
||||
- `docs/testing/authentication-manual-acceptance.md`.
|
||||
|
||||
Do not infer authorization for server, Nginx, Authentik, database, credential, or cutover changes
|
||||
from an automated PASS.
|
||||
|
||||
## Verification status
|
||||
|
||||
- The P1.1 workspace-directory registry and P2–P6 preprocessing workstreams are implemented and
|
||||
have automated coverage.
|
||||
- Evidence restructuring has a real PSD acceptance PASS as recorded above.
|
||||
- AI Description Generation has automated coverage across installation setup, model selection,
|
||||
generation/consolidation scopes, bounded sampling, cancellation/recovery, history, SSE/polling,
|
||||
and the LiteLLM helper boundary.
|
||||
- L2 tests requiring real providers or remote databases remain opt-in.
|
||||
- Server deployment, release, and owner-operated acceptance steps remain pending wherever the
|
||||
referenced runbooks require explicit approval.
|
||||
|
||||
Run the layer-specific checks documented in `AGENTS.md`. For release-sensitive changes, also run
|
||||
the repository contract scripts in `scripts/` and build the MkDocs site.
|
||||
|
||||
## Operational invariants
|
||||
|
||||
- `tht`'s `-c`/`--config` option follows the subcommand; it is not a global option.
|
||||
- `--json` commands write pristine JSON to stdout.
|
||||
- Persisted phase documents and the decision ledger are the source of session truth; chat is not.
|
||||
- UI chrome is English; workspace document content retains the workspace language.
|
||||
- The backend refuses resume for finalized or archived sessions.
|
||||
- A resume must send `/riprendi-sessione <id>`; a new session must send `/nuova-domanda`.
|
||||
- DWH access is read-only.
|
||||
# Project state
|
||||
|
||||
Updated: 2026-09-15. This is a current snapshot, not a release diary. Stable commands
|
||||
and invariants are in [AGENTS.md](AGENTS.md); prior snapshots remain in Git.
|
||||
|
||||
## Current contracts
|
||||
|
||||
- React supports full/embedded rendering independently of local/OIDC/upstream auth,
|
||||
with EN/IT UI and immutable session interaction language. See
|
||||
[application shell](docs/architecture/application-shell.md) and
|
||||
[localization](docs/operations/shell-and-localization.md).
|
||||
- PostgreSQL Metadata Catalog owns database identity, binding, schema, descriptions,
|
||||
sensitivity and relationships for all core consumers. Workspace schema v4 contains
|
||||
identity and optional Evidence only. Installation schema v2 is the authored model
|
||||
catalog source. See [overview](docs/architecture/overview.md) and
|
||||
[model configuration](docs/general/pi-configuration.md).
|
||||
- The harness owns workflow persistence; chat is not the durable session record.
|
||||
Memory uses PostgreSQL authority and derived Qdrant dense/BM25 search. Editable
|
||||
Evidence has local archive authority and manual consolidation. File save, search
|
||||
activation and Git publication have distinct outcomes. See
|
||||
[Memory](docs/gestione-memory.md), [Evidence](docs/contracts/curated-evidence-v4.md)
|
||||
and [consolidated release evidence](docs/reports/knowledge-archives-release.md).
|
||||
- Reference preprocessing must not clear Memory. Use the installation-scoped
|
||||
`tht --installation /absolute/path/thothii-installation.yaml workspace preprocess run`
|
||||
and its [contract](docs/contracts/workspace-preprocessing-cli.md).
|
||||
- DWH sessions are read-only. SSH tunnels support database-management diagnostics
|
||||
and metadata synchronization, not NL→SQL session creation; use direct or REST
|
||||
transport for sessions.
|
||||
|
||||
## Installation and workspace boundaries
|
||||
|
||||
Fresh standalone installations follow the manual terminal procedures in
|
||||
[Italian](docs/install/standalone-manual-it.md) or
|
||||
[English](docs/install/standalone-manual-en.md), without an installer or launcher.
|
||||
The [Compose reference](docs/operations/compose-reference.md) is for maintainers,
|
||||
not another quick start. Catalog and Memory migrations are explicit.
|
||||
|
||||
Descriptors, authentication, provider credentials, certificates and runtime bindings
|
||||
stay in protected installation-local paths. Do not copy secrets into examples or
|
||||
workspace Git. Legacy runtime snapshots may use absolute paths and protected
|
||||
`harness/.env`; do not silently relocate them.
|
||||
|
||||
PSD authoring is separate at `/Users/mp/projects/tht-workspace-psd`. Its GitHub
|
||||
repository was copied to private Gitea
|
||||
[workspace_psd](https://git.tylconsulting.it/mptyl/workspace_psd), preserving both
|
||||
branches. It is a copy, not automatic synchronization. Running installations were
|
||||
not repointed to a different workspace remote.
|
||||
|
||||
## Recorded deployments and server authority
|
||||
|
||||
Use the ordered [server handoff](docs/operations/server-codex-handoff.md) for
|
||||
coordinated ThothII/Omics upgrades. Omics integration uses GitHub
|
||||
`Dallavilla-Tiziano/omics_portal`, with no Gitea relay prerequisite. Omics uses
|
||||
embedded/upstream identity, not another ThothII OIDC login. Read
|
||||
[upstream authentication](docs/install/authentication-upstream.md) before changes.
|
||||
|
||||
Last recorded application deliveries (not a fresh runtime attestation):
|
||||
|
||||
- [Session dialogs](docs/reports/2026-09-14-session-dialogs-release.md):
|
||||
`b1723c34-session-dialogs-20260914`, frontend-only.
|
||||
- [Session layout/Memory fix](docs/reports/2026-09-14-session-layout-memory-fix.md):
|
||||
`49333a2d-session-memory-fix`, core/frontend.
|
||||
|
||||
Keep those reports and rollback instructions while operator gates remain open.
|
||||
A later deployment does not prove every earlier acceptance item passed.
|
||||
|
||||
## Remaining acceptance and design gates
|
||||
|
||||
- Fresh-machine Mac, Windows/WSL2 and Linux installation acceptance, including real
|
||||
DWH/model endpoints, remains a separate operator exercise.
|
||||
- Real IdP/portal login, logout, embedded interaction and PSD semantic acceptance
|
||||
follow the [manual matrix](docs/testing/authentication-manual-acceptance.md) and
|
||||
delivery reports; synthetic tests do not close them.
|
||||
- [Security hardening](docs/plans/2026-09-08-security-hardening-prd.md) is a draft.
|
||||
Revalidate SEC01–12 and obtain design approval before implementation or real
|
||||
server/IdP/DWH mutation.
|
||||
- Optional NER remains opt-in; labeled Italian quality, benchmark and licensing
|
||||
acceptance are not implied by document cleanup.
|
||||
- Semantic aliases, value descriptions, synonyms/concepts, dialect and multi-schema
|
||||
extensions remain explicit design work. Current sensitivity delivery follows the
|
||||
Catalog contract; additional policies require their own acceptance.
|
||||
- Legacy database UI fallback (`?db-ui=legacy`, dev/staging) and prototype removal
|
||||
remain subject to owner acceptance.
|
||||
|
||||
## Documentation maintenance
|
||||
|
||||
MkDocs publishes only 20 product/operator pages and five approved assets.
|
||||
Architecture, contracts, ADRs, plans, research, tests and release evidence are
|
||||
excluded from HTML and search. The repository itself is public: editorial exclusion
|
||||
is not confidentiality.
|
||||
|
||||
The [cleanup record](docs/maintenance/2026-09-15-documentation-cleanup.md) records
|
||||
retired sources and retained gates. Main contains source; Actions generates the
|
||||
`pages` branch. The live site requires the separate explicit deployment described
|
||||
in [public manual publication](docs/operations/public-docs-publication.md).
|
||||
|
||||
@@ -4,72 +4,52 @@ ThothII is a human-reviewed NL-to-SQL workflow with a React frontend and a Fasti
|
||||
core. The portable deployment runs two application services plus the installation-local metadata
|
||||
catalog; DWH and LLM services remain external. Semantic services are bundled in Compose.
|
||||
|
||||
Authentication is configured through the single host CLI tht: see the [local authentication guide](docs/install/authentication-local.md),
|
||||
[generic OIDC guide](docs/install/authentication-oidc.md), and [manual acceptance matrix](docs/testing/authentication-manual-acceptance.md).
|
||||
The same frontend supports **full** (its own header) and **embedded** (inside a
|
||||
portal). This choice is independent of authentication: the Mac uses full/local,
|
||||
Omics uses embedded/upstream with its existing login, and a standalone server
|
||||
can use full/OIDC. See [rendering architecture](docs/architecture/application-shell.md)
|
||||
and [configuration, Omics delivery and deploy](docs/operations/shell-and-localization.md).
|
||||
|
||||
## Docker Compose: local startup
|
||||
For the current server upgrade with Omics Portal, follow the ordered
|
||||
[Codex server handoff](docs/operations/server-codex-handoff.md), including source
|
||||
integration, embedded/upstream configuration, coordinated rollout and rollback.
|
||||
|
||||
Requirements: Docker Engine with Compose v2. The mandatory stack is `frontend`, `core`,
|
||||
`catalog-db`, `qdrant`, `embedding`, and the one-shot `embedding-model-init`. DWH and LLM remain external,
|
||||
configurable endpoints—even when they are co-located with ThothII.
|
||||
Local/OIDC authentication is configured through the host CLI `tht`; portal
|
||||
authentication is established by the trusted server proxy. See the
|
||||
[local guide](docs/install/authentication-local.md),
|
||||
[OIDC guide](docs/install/authentication-oidc.md),
|
||||
[upstream integration](docs/install/authentication-upstream.md), and
|
||||
[manual acceptance matrix](docs/testing/authentication-manual-acceptance.md).
|
||||
|
||||
From a fresh clone, run these commands from the repository root:
|
||||
For the clone-based manual standalone installation test on macOS, Windows, and Linux, use the
|
||||
[Italian procedure](docs/install/standalone-manual-it.md) or the
|
||||
[English procedure](docs/install/standalone-manual-en.md).
|
||||
|
||||
```sh
|
||||
cp deploy/env/local.env.example deploy/env/local.env
|
||||
# Copy docs/install/examples/thothii-installation.local.yaml to a protected operator path,
|
||||
# replace its placeholders, chmod it 600, and set that exact THT_INSTALLATION_CONFIG_SOURCE.
|
||||
# Edit deploy/env/local.env, including PI_AUTH_FILE, THT_SECRETS_FILE, and external endpoints.
|
||||
./scripts/run-stack.sh
|
||||
```
|
||||
The [public manual](https://git.tylconsulting.it/thothii-docs/) covers the product,
|
||||
installation, use and administration. Developer architecture, contracts, ADRs, tests,
|
||||
plans and release records remain in this repository but are excluded from MkDocs
|
||||
pages and search. This is an editorial boundary, not an access restriction on the
|
||||
public repository. See the [documentation cleanup review](docs/maintenance/2026-09-15-documentation-cleanup.md)
|
||||
for the executed consolidation and the inventory of historical sources retained in Git.
|
||||
|
||||
The launcher builds the core, starts `catalog-db`, runs the explicit one-shot Kysely migrations,
|
||||
then runs the base+local stack in the foreground. Migrations never run implicitly in backend
|
||||
startup. The core image contains its Pi runtime; no host `pi` executable is used. For a server
|
||||
installation, build the image, start the catalog, and run the same migration service before the
|
||||
application rollout:
|
||||
## Docker Compose and installation
|
||||
|
||||
```sh
|
||||
cp deploy/env/server.env.example deploy/env/server.env
|
||||
# Prepare a mode-600 thothii-installation.yaml from the server example and set its exact
|
||||
# path as THT_INSTALLATION_CONFIG_SOURCE. Edit all remaining storage/secret/endpoint paths.
|
||||
sudo scripts/prepare-server-pi-state.sh /srv/thothii/pi-state 10001 10001
|
||||
docker compose --env-file deploy/env/server.env \
|
||||
-f compose.yaml -f deploy/compose.server.yaml \
|
||||
-f deploy/compose.session-server.yaml.example build core
|
||||
docker compose --env-file deploy/env/server.env \
|
||||
-f compose.yaml -f deploy/compose.server.yaml \
|
||||
-f deploy/compose.session-server.yaml.example up -d catalog-db
|
||||
docker compose --env-file deploy/env/server.env \
|
||||
-f compose.yaml -f deploy/compose.server.yaml \
|
||||
-f deploy/compose.session-server.yaml.example run --rm catalog-migrate
|
||||
docker compose --env-file deploy/env/server.env \
|
||||
-f compose.yaml -f deploy/compose.server.yaml \
|
||||
-f deploy/compose.session-server.yaml.example up --build -d
|
||||
```
|
||||
For a fresh installation, follow the guided terminal procedure in
|
||||
[Italian](docs/install/standalone-manual-it.md) or
|
||||
[English](docs/install/standalone-manual-en.md). The single
|
||||
`tht setup --complete` command validates protected files, builds the images, runs
|
||||
Catalog migration, starts the stack and imports the configured workspace repository.
|
||||
There is no graphical installer or native launcher.
|
||||
|
||||
The initializer is required for an empty or restored server Pi-state bind. It atomically creates
|
||||
the three regular targets hidden below the writable parent bind; protected Pi auth and tracked
|
||||
model/settings sources remain separate read-only mounts. See the server manual before substituting
|
||||
a root other than `/srv/thothii/pi-state`.
|
||||
The mandatory stack includes frontend, core, PostgreSQL catalog, Qdrant, Ollama
|
||||
and the embedding initializer. DWH and LLM endpoints remain external dependencies.
|
||||
Pi is included in the core image. Credentials and certificates belong in protected
|
||||
installation-local files, never in the workspace repository.
|
||||
|
||||
Workspace descriptors come from the Git remote configured by `THT_WORKSPACE_GIT_REMOTE`; their
|
||||
runtime endpoint and secret bindings remain installation-local. Open
|
||||
<http://127.0.0.1:8080> (set `THOTH_HTTP_PORT` in `deploy/env/local.env` to choose another
|
||||
loopback port).
|
||||
|
||||
Credentials and certificates are local protected files. Do not put them in environment examples,
|
||||
workspace YAML, URLs, or Compose interpolation values.
|
||||
|
||||
Application state is split across the named `settings`, `pi-state`, `workspace-registry`,
|
||||
`sessions`, `qdrant-data`, and `embedding-models` volumes. `docker compose down` keeps them.
|
||||
`qdrant-data` is a derived but persistent index store; `embedding-models` is an Ollama model
|
||||
cache for `qwen3-embedding:0.6b` with fixed `1024`-dimension embeddings. Only an explicit destructive command such as `docker compose
|
||||
down --volumes` removes them.
|
||||
|
||||
The frontend depends on the core health check and proxies `/health` and `/api/*` to it. The
|
||||
application health endpoint intentionally checks process readiness only; external dependency
|
||||
diagnostics are exposed by `tht doctor` and do not prevent the UI from starting.
|
||||
For developer topology, overlays and lifecycle details, see the internal
|
||||
[Compose reference](docs/operations/compose-reference.md). Ordinary stop/down keeps
|
||||
persistent data; removing volumes is destructive and is not an upgrade step.
|
||||
Process health is distinct from external dependency checks performed by doctor.
|
||||
|
||||
## Git-backed workspace repository
|
||||
|
||||
|
||||
@@ -41,8 +41,11 @@ const runtimeModelSchema = z.object({
|
||||
supportsReasoningEffort: z.boolean(),
|
||||
supportsStore: z.boolean(),
|
||||
maxTokensField: z.string().optional(),
|
||||
thinkingFormat: z.enum(["qwen", "qwen-chat-template"]).optional(),
|
||||
}).strict().optional(),
|
||||
}).strict().optional(),
|
||||
}).strict().refine((session) => !session.compatibility?.thinkingFormat || session.reasoning, {
|
||||
message: "thinkingFormat requires reasoning: true",
|
||||
}).optional(),
|
||||
metadataGeneration: z.object({ disableThinking: z.boolean() }).strict().optional(),
|
||||
}).strict();
|
||||
|
||||
|
||||
@@ -16,12 +16,16 @@ import { loadSettings } from "./settings/settings-store.js";
|
||||
import { ThtRunner, type SessionRow } from "./tht/tht-runner.js";
|
||||
import { WorkspaceRegistry } from "./workspaces/registry.js";
|
||||
import { WorkspaceSecretStore } from "./workspaces/secret-store.js";
|
||||
import { createProductionWorkspaceDiagnoser } from "./workspaces/diagnostics.js";
|
||||
import { resolveCatalogRuntimeBinding } from "./catalog/runtime-binding.js";
|
||||
import { CatalogService } from "./catalog/service.js";
|
||||
import { validateOperationalWorkspace } from "./workspaces/schema.js";
|
||||
import { createCatalogRepository } from "./catalog/repository.js";
|
||||
import type { CatalogRepository } from "./catalog/types.js";
|
||||
|
||||
type OperatorAction = "maintenance-activate" | "maintenance-deactivate" | "maintenance-status"
|
||||
| "session-inventory" | "workflow-doctor" | "workspace-integrity"
|
||||
| "pi-test" | "effective-settings";
|
||||
| "workspace-pull" | "workspace-test" | "pi-test" | "effective-settings";
|
||||
|
||||
const lifecyclePrincipal: PrincipalContext = {
|
||||
issuer: "tht-operator-command",
|
||||
@@ -119,6 +123,119 @@ async function workspaceIntegrity(config: AppConfig): Promise<{
|
||||
return { ready: true, ...integrity };
|
||||
}
|
||||
|
||||
async function workspacePull(config: AppConfig): Promise<{
|
||||
ready: boolean;
|
||||
status: "succeeded" | "degraded";
|
||||
branch: string;
|
||||
head?: string;
|
||||
degraded: boolean;
|
||||
}> {
|
||||
const status = await new WorkspaceRegistry(config.workspaceRegistry).pull();
|
||||
return {
|
||||
ready: !status.degraded,
|
||||
status: status.degraded ? "degraded" : "succeeded",
|
||||
branch: status.branch,
|
||||
...(status.head ? { head: status.head } : {}),
|
||||
degraded: status.degraded,
|
||||
};
|
||||
}
|
||||
|
||||
interface WorkspaceTestReport {
|
||||
id: string;
|
||||
status: "ready" | "failed";
|
||||
database: "reachable" | "not_configured" | "failed";
|
||||
diagnostics: string[];
|
||||
}
|
||||
|
||||
async function workspaceTest(config: AppConfig): Promise<{
|
||||
ready: boolean;
|
||||
workspaces: WorkspaceTestReport[];
|
||||
}> {
|
||||
if (!config.catalogDatabase) throw new Error("Catalog database is not configured");
|
||||
const registry = new WorkspaceRegistry(config.workspaceRegistry);
|
||||
const revisions = await registry.list();
|
||||
const repository = createCatalogRepository(config.catalogDatabase);
|
||||
try {
|
||||
const secretStore = new WorkspaceSecretStore({
|
||||
root: config.workspaceSecretStoreRoot,
|
||||
runtimeRoot: config.workspaceSecretRuntimeRoot,
|
||||
installationId: config.workspaceRegistry.installationId,
|
||||
});
|
||||
const catalogService = new CatalogService(
|
||||
repository,
|
||||
registry,
|
||||
secretStore,
|
||||
config.workspaceRegistry.secretRoots,
|
||||
config.workspaceDiagnosticTimeoutMs,
|
||||
);
|
||||
const diagnose = createProductionWorkspaceDiagnoser(config.workspaceDiagnosticTimeoutMs, undefined, {
|
||||
internalQdrantUrl: config.internalQdrantUrl,
|
||||
internalEmbeddingUrl: config.internalEmbeddingUrl,
|
||||
internalEmbeddingId: config.internalEmbeddingId,
|
||||
internalEmbeddingModel: config.internalEmbeddingModel,
|
||||
internalEmbeddingDimensions: config.internalEmbeddingDimensions,
|
||||
});
|
||||
const databases = await repository.list();
|
||||
const reports: WorkspaceTestReport[] = [];
|
||||
for (const revision of revisions) {
|
||||
const diagnostics: string[] = [];
|
||||
let workspace: ReturnType<typeof validateOperationalWorkspace>;
|
||||
try {
|
||||
workspace = validateOperationalWorkspace((await registry.read(revision.id)).workspace);
|
||||
} catch {
|
||||
reports.push({ id: revision.id, status: "failed", database: "not_configured", diagnostics: ["workspace_invalid"] });
|
||||
continue;
|
||||
}
|
||||
const database = databases.find((candidate) => candidate.workspaceId === revision.id);
|
||||
if (!database) {
|
||||
reports.push({ id: revision.id, status: "failed", database: "not_configured", diagnostics: ["database_binding_missing"] });
|
||||
continue;
|
||||
}
|
||||
let tested;
|
||||
try {
|
||||
tested = await catalogService.test(database);
|
||||
} catch {
|
||||
reports.push({ id: revision.id, status: "failed", database: "failed", diagnostics: ["database_unreachable"] });
|
||||
continue;
|
||||
}
|
||||
if (!tested || tested.connectionStatus !== "reachable") {
|
||||
reports.push({ id: revision.id, status: "failed", database: "failed", diagnostics: ["database_unreachable"] });
|
||||
continue;
|
||||
}
|
||||
let lease: ReturnType<typeof resolveCatalogRuntimeBinding>;
|
||||
try {
|
||||
lease = resolveCatalogRuntimeBinding({
|
||||
workspace,
|
||||
database: tested,
|
||||
environment: process.env,
|
||||
secretRoots: config.workspaceRegistry.secretRoots,
|
||||
secretStore,
|
||||
});
|
||||
} catch {
|
||||
reports.push({ id: revision.id, status: "failed", database: "reachable", diagnostics: ["binding_missing"] });
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
// CatalogService.test() above is the authoritative database probe and records its
|
||||
// outcome. The remaining diagnoser pass checks Evidence and internal semantic services;
|
||||
// skipping its legacy DWH probe avoids requiring a second response-shape contract for a
|
||||
// REST health endpoint.
|
||||
const result = await diagnose(lease.workspace, lease.bindings, { writeProbe: false, skipDwh: true });
|
||||
diagnostics.push(...result.diagnostics.map((diagnostic) => diagnostic.code));
|
||||
const ready = result.activatable;
|
||||
reports.push({ id: revision.id, status: ready ? "ready" : "failed", database: "reachable", diagnostics });
|
||||
} catch {
|
||||
reports.push({ id: revision.id, status: "failed", database: "reachable", diagnostics: ["connector_unavailable"] });
|
||||
} finally {
|
||||
lease.release();
|
||||
}
|
||||
}
|
||||
return { ready: reports.length > 0 && reports.every((report) => report.status === "ready"), workspaces: reports };
|
||||
} finally {
|
||||
await repository.close?.();
|
||||
}
|
||||
}
|
||||
|
||||
export async function runOperatorAction(
|
||||
action: OperatorAction,
|
||||
config: AppConfig,
|
||||
@@ -132,6 +249,8 @@ export async function runOperatorAction(
|
||||
if (action === "session-inventory") return await sessionInventory(config);
|
||||
if (action === "workflow-doctor") return await workflowDiagnostics(config);
|
||||
if (action === "workspace-integrity") return await workspaceIntegrity(config);
|
||||
if (action === "workspace-pull") return await workspacePull(config);
|
||||
if (action === "workspace-test") return await workspaceTest(config);
|
||||
const modelCatalog = loadRuntimeModelCatalog(config.modelCatalogFile);
|
||||
if (action === "effective-settings") {
|
||||
return effectiveSettings(config, loadSettings(config), modelCatalog);
|
||||
@@ -146,6 +265,7 @@ async function main(): Promise<void> {
|
||||
if (!action || ![
|
||||
"maintenance-activate", "maintenance-deactivate", "maintenance-status", "session-inventory",
|
||||
"workflow-doctor", "workspace-integrity", "pi-test", "effective-settings",
|
||||
"workspace-pull", "workspace-test",
|
||||
].includes(action)) throw new Error("invalid operator action");
|
||||
const result = await runOperatorAction(action, loadConfig(process.env));
|
||||
process.stdout.write(`${JSON.stringify(result)}\n`);
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface SessionRuntime {
|
||||
}
|
||||
|
||||
export interface RuntimeOptions {
|
||||
interactionLanguage?: string | null;
|
||||
provider?: string;
|
||||
model?: string;
|
||||
thinking?: string;
|
||||
@@ -48,6 +49,7 @@ export class PiProcessManager {
|
||||
private spawnFn: (
|
||||
sessionId: string, author: string, provider: string | undefined, model: string | undefined,
|
||||
principal?: PrincipalContext, runtimeConfigPath?: string,
|
||||
interactionLanguage?: string | null,
|
||||
) => ChildProcessWithoutNullStreams;
|
||||
private loadAuthProviders: (agentDir: string) => ReadonlySet<string>;
|
||||
private modelCatalog: RuntimeModelCatalog;
|
||||
@@ -67,11 +69,11 @@ export class PiProcessManager {
|
||||
this.loadAuthProviders = opts?.authProviders
|
||||
?? ((agentDir) => loadPiAuthProviders({ agentDir }));
|
||||
if (opts?.spawnFn) {
|
||||
this.spawnFn = (sessionId, author, provider, model, principal, runtimeConfigPath) =>
|
||||
this.spawnPi(opts.spawnFn!, sessionId, author, provider, model, principal, runtimeConfigPath);
|
||||
this.spawnFn = (sessionId, author, provider, model, principal, runtimeConfigPath, language) =>
|
||||
this.spawnPi(opts.spawnFn!, sessionId, author, provider, model, principal, runtimeConfigPath, language);
|
||||
} else {
|
||||
this.spawnFn = (sessionId, author, provider, model, principal, runtimeConfigPath) =>
|
||||
this.spawnPi(nodeSpawn, sessionId, author, provider, model, principal, runtimeConfigPath);
|
||||
this.spawnFn = (sessionId, author, provider, model, principal, runtimeConfigPath, language) =>
|
||||
this.spawnPi(nodeSpawn, sessionId, author, provider, model, principal, runtimeConfigPath, language);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +87,7 @@ export class PiProcessManager {
|
||||
private spawnPi(
|
||||
spawnFn: SpawnFn, sessionId: string, author: string, provider: string | undefined,
|
||||
model: string | undefined, principal?: PrincipalContext, runtimeConfigPath?: string,
|
||||
interactionLanguage?: string | null,
|
||||
): ChildProcessWithoutNullStreams {
|
||||
// This is the final shared boundary for createFor(), spawnFor(), and resume(). Validate
|
||||
// before auth-provider inspection, then make Pi consume the exact copied bytes rather than
|
||||
@@ -110,6 +113,9 @@ export class PiProcessManager {
|
||||
additions: { THT_SESSION: sessionId, THT_AUTHOR: author },
|
||||
});
|
||||
env.PI_CODING_AGENT_DIR = agent.agentDir;
|
||||
// A launch hint only: the gate reads the authoritative manifest before each turn.
|
||||
delete env.THT_INTERACTION_LANGUAGE;
|
||||
if (interactionLanguage) env.THT_INTERACTION_LANGUAGE = interactionLanguage;
|
||||
env.PI_CODING_AGENT_SESSION_DIR = agent.sessionDir;
|
||||
clearPrincipalEnvironment(env);
|
||||
if (principal) Object.assign(env, principalEnvironment(principal));
|
||||
@@ -187,7 +193,9 @@ export class PiProcessManager {
|
||||
const model = o.model ?? this.cfg.defaults.model;
|
||||
let child: ChildProcessWithoutNullStreams;
|
||||
try {
|
||||
child = this.spawnFn(sessionId, author, provider, model, o.principal, o.runtimeConfig?.path);
|
||||
child = this.spawnFn(
|
||||
sessionId, author, provider, model, o.principal, o.runtimeConfig?.path, o.interactionLanguage,
|
||||
);
|
||||
} catch (error) {
|
||||
o.runtimeConfig?.release();
|
||||
throw error;
|
||||
@@ -296,8 +304,13 @@ export class PiProcessManager {
|
||||
}
|
||||
|
||||
async resume(sessionId: string, tht: ThtRunner): Promise<SessionRuntime> {
|
||||
const manifest = await tht.sessionShow(sessionId) as { provider?: string; model?: string; thinking?: string } | null;
|
||||
const manifest = await tht.sessionShow(sessionId) as {
|
||||
provider?: string; model?: string; thinking?: string; interaction_language?: string | null;
|
||||
} | null;
|
||||
const language = manifest?.interaction_language
|
||||
?? (await tht.ensureInteractionLanguage(sessionId)).interaction_language;
|
||||
return this.spawnFor(sessionId, {
|
||||
interactionLanguage: language,
|
||||
provider: manifest?.provider,
|
||||
model: manifest?.model,
|
||||
thinking: manifest?.thinking,
|
||||
|
||||
@@ -13,6 +13,7 @@ import type { MaintenanceBarrier } from "../runtime/maintenance-gate.js";
|
||||
import { hasPermission, isPrincipalContext, requirePermission } from "../auth/authorization.js";
|
||||
import { splitCanonicalModelId, type RuntimeModelCatalog } from "../models/runtime-model-catalog.js";
|
||||
import type { CatalogRepository } from "../catalog/types.js";
|
||||
import { interactionLanguage } from "../tht/interaction-language.js";
|
||||
|
||||
const BOOTSTRAP_FAILURE_MESSAGE =
|
||||
"Session startup failed. Check configuration and connectivity, then Resume the session.";
|
||||
@@ -381,8 +382,13 @@ export function sessionRoutes(
|
||||
app.post("/sessions", async (req, reply) => {
|
||||
const b = req.body as {
|
||||
question: string; name?: string; workspace?: string; workspaceId?: string;
|
||||
provider?: string; model?: string; thinking?: string;
|
||||
provider?: string; model?: string; thinking?: string; interactionLanguage?: unknown;
|
||||
};
|
||||
const language = interactionLanguage(b?.interactionLanguage);
|
||||
if (!language) return reply.code(400).send({
|
||||
code: "invalid_interaction_language",
|
||||
error: "interactionLanguage must be a well-formed BCP-47 language tag",
|
||||
});
|
||||
if ((b.provider === undefined) !== (b.model === undefined)
|
||||
|| (b.provider !== undefined && (typeof b.provider !== "string" || typeof b.model !== "string" || !b.provider || !b.model))) {
|
||||
return reply.code(400).send({ error: "provider and model must be supplied together" });
|
||||
@@ -503,11 +509,15 @@ export function sessionRoutes(
|
||||
// registry snapshot. The legacy fallback stays available for sessions created before
|
||||
// the browser-local preference migration.
|
||||
let id: string;
|
||||
let sessionLanguage = language;
|
||||
try {
|
||||
({ id } = await runner.sessionNew({
|
||||
const created = await runner.sessionNew({
|
||||
question: b.question, name: b.name, workspaceConfigPath,
|
||||
workspaceId, workspaceRevision, provider, model, thinking,
|
||||
}));
|
||||
interactionLanguage: language,
|
||||
});
|
||||
id = created.id;
|
||||
sessionLanguage = created.interaction_language ?? language;
|
||||
manifestPersisted = true;
|
||||
if (revisionLease) {
|
||||
await revisionLease.markPersisted().catch((error: unknown) => {
|
||||
@@ -520,6 +530,7 @@ export function sessionRoutes(
|
||||
} catch { return storageFailure(reply); }
|
||||
const options = {
|
||||
provider, model, thinking,
|
||||
interactionLanguage: sessionLanguage,
|
||||
author: principal.displayName ?? principal.subject,
|
||||
principal,
|
||||
question: b.question,
|
||||
@@ -664,6 +675,13 @@ export function sessionRoutes(
|
||||
app.post("/sessions/:id/resume", async (req, reply) => {
|
||||
const id = (req.params as any).id;
|
||||
const principal = getPrincipal(req);
|
||||
if (Object.hasOwn(req.body ?? {}, "interactionLanguage")
|
||||
|| Object.hasOwn(req.body ?? {}, "interaction_language")) {
|
||||
return reply.code(400).send({
|
||||
code: "interaction_language_pinned",
|
||||
error: "Resume uses the session's persisted interaction language; overrides are not accepted",
|
||||
});
|
||||
}
|
||||
return withSessionLifecycle(id, async () => {
|
||||
let settings: Settings;
|
||||
let located: LocatedSession | undefined;
|
||||
@@ -681,6 +699,7 @@ export function sessionRoutes(
|
||||
const saved = manifest as {
|
||||
provider?: string; model?: string; thinking?: string;
|
||||
workspace_id?: string; workspace_revision?: string;
|
||||
interaction_language?: string | null;
|
||||
};
|
||||
const requested = (req.body ?? {}) as { provider?: string; model?: string; thinking?: string };
|
||||
if ((requested.provider === undefined) !== (requested.model === undefined)
|
||||
@@ -719,6 +738,12 @@ export function sessionRoutes(
|
||||
});
|
||||
}
|
||||
try { settings = await d.getSettings(principal); } catch { return storageFailure(reply); }
|
||||
let language = saved.interaction_language;
|
||||
if (language == null) {
|
||||
try {
|
||||
language = (await runner.ensureInteractionLanguage(id, workspaceConfigPath)).interaction_language;
|
||||
} catch { return reply.code(503).send({ error: RESUME_FAILURE_MESSAGE }); }
|
||||
}
|
||||
// This check belongs inside the per-session lock: a preceding cold Resume may have
|
||||
// installed a running runtime while this request was waiting.
|
||||
const existing = d.mgr.get(id);
|
||||
@@ -737,6 +762,7 @@ export function sessionRoutes(
|
||||
});
|
||||
const options = {
|
||||
provider: selected.provider,
|
||||
interactionLanguage: language,
|
||||
model: selected.model,
|
||||
thinking: saved?.thinking ?? settings.thinking,
|
||||
author: principal.displayName ?? principal.subject,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/** Validate/canonicalize the tag; available translation catalogs belong to the UI. */
|
||||
export function interactionLanguage(value: unknown): string | undefined {
|
||||
if (typeof value !== "string") return undefined;
|
||||
try {
|
||||
const [canonical] = Intl.getCanonicalLocales(value);
|
||||
return canonical;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ export interface SessionRow {
|
||||
author: string | null;
|
||||
workspace_id?: string | null;
|
||||
workspace_revision?: string | null;
|
||||
interaction_language?: string | null;
|
||||
archived?: boolean;
|
||||
}
|
||||
|
||||
@@ -482,6 +483,7 @@ export class ThtRunner {
|
||||
|
||||
async sessionNew(o: {
|
||||
question: string;
|
||||
interactionLanguage?: string;
|
||||
provider?: string;
|
||||
model?: string;
|
||||
thinking?: string;
|
||||
@@ -497,6 +499,7 @@ export class ThtRunner {
|
||||
["--provider", o.provider],
|
||||
["--model", o.model],
|
||||
["--thinking", o.thinking],
|
||||
["--interaction-language", o.interactionLanguage],
|
||||
["--name", o.name],
|
||||
["--workspace-id", o.workspaceId],
|
||||
["--workspace-revision", o.workspaceRevision],
|
||||
@@ -504,7 +507,7 @@ export class ThtRunner {
|
||||
if (v) a.push(f, v);
|
||||
}
|
||||
a.push("--json");
|
||||
return this.json<{ id: string }>(a, o.workspaceConfigPath ?? o.workspace);
|
||||
return this.json<{ id: string; interaction_language?: string }>(a, o.workspaceConfigPath ?? o.workspace);
|
||||
}
|
||||
|
||||
/** Build and persist the deterministic F1 retrieval pack for a new session. */
|
||||
@@ -533,6 +536,12 @@ export class ThtRunner {
|
||||
return this.json<unknown>(["session", "show", id, "--json"], workspace);
|
||||
}
|
||||
|
||||
ensureInteractionLanguage(id: string, workspace?: string) {
|
||||
return this.json<{ interaction_language: string }>(
|
||||
["session", "ensure-interaction-language", id, "--json"], workspace,
|
||||
);
|
||||
}
|
||||
|
||||
sqlPreview(id: string, p: { limit?: number; offset?: number }, workspace?: string) {
|
||||
// No positional FILE: the harness resolves sql_final.sql from the session
|
||||
// via _session_sql_file(cfg, session_id), which respects the workspace path.
|
||||
|
||||
@@ -36,7 +36,7 @@ test("loop F1: crea sessione → SSE riceve il widget → risponde → il modell
|
||||
ollamaEnsure: async () => ({ ok: true }),
|
||||
searchPack: async () => {},
|
||||
sessionNew: async () => ({ id: "s1" }),
|
||||
sessionShow: async (_id: string) => ({ id: "s1", provider: undefined, model: undefined, thinking: undefined }),
|
||||
sessionShow: async (_id: string) => ({ id: "s1", interaction_language: "en", provider: undefined, model: undefined, thinking: undefined }),
|
||||
sessionList: async () => [],
|
||||
} as any,
|
||||
spawnFn: () => spawn("node", [FAKE, SCRIPT]) as any,
|
||||
@@ -48,7 +48,7 @@ test("loop F1: crea sessione → SSE riceve il widget → risponde → il modell
|
||||
const created = await fetch(`${base}/sessions`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ workspace: "w", question: "q" }),
|
||||
body: JSON.stringify({ workspace: "w", question: "q", interactionLanguage: "en" }),
|
||||
});
|
||||
expect(created.status).toBe(200);
|
||||
|
||||
|
||||
@@ -95,6 +95,35 @@ test("returns empty catalogs when no runtime projection is configured", () => {
|
||||
expect(loadMetadataGenerationModels({}).catalog()).toEqual({ models: [], default: null });
|
||||
});
|
||||
|
||||
test.each([
|
||||
["qwen-chat-template", true, true],
|
||||
["qwen", true, true],
|
||||
["qwen-typo", true, false],
|
||||
["qwen-chat-template", false, false],
|
||||
])("validates Qwen thinking format %s with reasoning=%s", (thinkingFormat, reasoning, valid) => {
|
||||
const { catalogFile } = runtimeCatalog({
|
||||
defaultInteraction: "local/qwen",
|
||||
models: [{
|
||||
id: "local/qwen", provider: "local", model: "qwen", label: "Qwen",
|
||||
upstreamModel: "qwen", endpoint: { baseUrl: "http://localhost:8000/v1" },
|
||||
authentication: { mode: "none" }, sessionAdapter: { mode: "openai_compatible" },
|
||||
session: {
|
||||
reasoning, contextWindow: 32768, maxTokens: 8192,
|
||||
compatibility: {
|
||||
supportsDeveloperRole: false, supportsReasoningEffort: false,
|
||||
supportsStore: false, maxTokensField: "max_tokens", thinkingFormat,
|
||||
},
|
||||
},
|
||||
}],
|
||||
});
|
||||
if (valid) {
|
||||
expect(loadRuntimeModelCatalog(catalogFile).sessionModels()[0].session?.compatibility)
|
||||
.toMatchObject({ thinkingFormat });
|
||||
} else {
|
||||
expect(() => loadRuntimeModelCatalog(catalogFile)).toThrow("runtime model catalog is invalid");
|
||||
}
|
||||
});
|
||||
|
||||
test("rejects a drifted default and an unprotected projection", () => {
|
||||
const drifted = runtimeCatalog({ defaultInteraction: "zai/missing" });
|
||||
expect(() => loadRuntimeModelCatalog(drifted.catalogFile)).toThrow("interaction default is invalid");
|
||||
|
||||
@@ -36,6 +36,10 @@ vi.mock("../src/tht/tht-runner.js", () => ({
|
||||
|
||||
vi.mock("../src/workspaces/registry.js", () => ({
|
||||
WorkspaceRegistry: class {
|
||||
async pull() {
|
||||
return { branch: "main", head: "a".repeat(40), ahead: 0, behind: 0, degraded: false };
|
||||
}
|
||||
|
||||
async listRetainedSnapshots() {
|
||||
return [{ snapshotPath: "/data/workspace-registry/snapshots/revision/workspace.yaml" }];
|
||||
}
|
||||
@@ -98,3 +102,13 @@ test("workflow doctor gives schema-v4 runtime rendering a live Catalog repositor
|
||||
expect(fakes.releaseWorkspaceRuntime).toHaveBeenCalledOnce();
|
||||
expect(fakes.catalogRepository.close).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test("workspace pull exposes only safe Git status", async () => {
|
||||
await expect(runOperatorAction("workspace-pull", config)).resolves.toEqual({
|
||||
ready: true,
|
||||
status: "succeeded",
|
||||
branch: "main",
|
||||
head: "a".repeat(40),
|
||||
degraded: false,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -190,6 +190,29 @@ test("Pi receives the leased workspace runtime config and releases it on direct
|
||||
expect(release).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test("Pi language launch hint comes from the session options and never ambient environment", () => {
|
||||
const previous = process.env.THT_INTERACTION_LANGUAGE;
|
||||
process.env.THT_INTERACTION_LANGUAGE = "it";
|
||||
const environments: NodeJS.ProcessEnv[] = [];
|
||||
const mgr = new PiProcessManager(loadConfig({}), {
|
||||
spawnFn: (_command, _args, options) => {
|
||||
environments.push(options.env);
|
||||
return recordingChild() as any;
|
||||
},
|
||||
});
|
||||
try {
|
||||
mgr.createFor("explicit-language", { interactionLanguage: "en" });
|
||||
mgr.teardown("explicit-language");
|
||||
mgr.createFor("manifest-resolved-in-gate");
|
||||
mgr.teardown("manifest-resolved-in-gate");
|
||||
expect(environments[0].THT_INTERACTION_LANGUAGE).toBe("en");
|
||||
expect(environments[1]).not.toHaveProperty("THT_INTERACTION_LANGUAGE");
|
||||
} finally {
|
||||
if (previous === undefined) delete process.env.THT_INTERACTION_LANGUAGE;
|
||||
else process.env.THT_INTERACTION_LANGUAGE = previous;
|
||||
}
|
||||
});
|
||||
|
||||
test("a close-only child event releases its temporary Pi agent snapshot", () => {
|
||||
const child = recordingChild();
|
||||
let snapshotDir: string | undefined;
|
||||
|
||||
@@ -53,7 +53,11 @@ const defaultWorkspaceRegistry = {
|
||||
|
||||
function buildApp(config: Parameters<typeof buildRealApp>[0], deps: Record<string, unknown> = {}) {
|
||||
const thtRunner = deps.thtRunner
|
||||
? { qdrantEnsure: async () => ({ ok: true }), ...(deps.thtRunner as object) }
|
||||
? {
|
||||
qdrantEnsure: async () => ({ ok: true }),
|
||||
ensureInteractionLanguage: async () => ({ interaction_language: "en" }),
|
||||
...(deps.thtRunner as object),
|
||||
}
|
||||
: undefined;
|
||||
return buildRealApp(config, {
|
||||
workspaceRuntimeSupport: () => true,
|
||||
@@ -88,6 +92,156 @@ const aliceHeaders = {
|
||||
"x-thoth-is-admin": "0",
|
||||
};
|
||||
|
||||
test.each([undefined, null, "", "en--US", "en_US", "en\nIGNORE", "en<script>", 42])(
|
||||
"new sessions reject invalid interaction language %s before persistence", async (interactionLanguage) => {
|
||||
const app = mutApp({ sessionNew: async () => { throw new Error("must not create"); } });
|
||||
try {
|
||||
const response = await app.inject({
|
||||
method: "POST", url: "/sessions", payload: { question: "Pazienti", interactionLanguage },
|
||||
});
|
||||
expect(response.statusCode).toBe(400);
|
||||
expect(response.json()).toMatchObject({ code: "invalid_interaction_language" });
|
||||
} finally { await app.close(); }
|
||||
},
|
||||
);
|
||||
|
||||
test.each([["en", "en"], ["fr-FR", "fr-FR"], ["FR-fr", "fr-FR"]])(
|
||||
"new session forwards canonical interaction language %s without changing the question", async (language, canonical) => {
|
||||
let created: any;
|
||||
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
|
||||
thtRunner: {
|
||||
sessionNew: async (options: any) => { created = options; return { id: "language" }; },
|
||||
searchPack: async () => {},
|
||||
},
|
||||
readiness: { ensure: async () => ({ ok: true }) },
|
||||
mgr: {
|
||||
get: () => undefined, createFor: () => ({ bridge: { onClientEvent: () => {} } }),
|
||||
configure: async () => {}, start: () => {},
|
||||
},
|
||||
getSettings: () => ({ workspace: "default" }),
|
||||
});
|
||||
try {
|
||||
const response = await app.inject({
|
||||
method: "POST", url: "/sessions", payload: { question: "Pazienti", interactionLanguage: language },
|
||||
});
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(created).toMatchObject({ question: "Pazienti", interactionLanguage: canonical });
|
||||
} finally { await app.close(); }
|
||||
});
|
||||
|
||||
test("resume rejects browser interaction language overrides", async () => {
|
||||
const app = mutApp({ sessionShow: async () => ({ status: "open", interaction_language: "it" }) });
|
||||
try {
|
||||
const response = await app.inject({
|
||||
method: "POST", url: "/sessions/s1/resume", payload: { interactionLanguage: "en" },
|
||||
});
|
||||
expect(response.statusCode).toBe(400);
|
||||
expect(response.json()).toMatchObject({ code: "interaction_language_pinned" });
|
||||
} finally { await app.close(); }
|
||||
});
|
||||
|
||||
test("new session starts Pi with the question language persisted by the harness", async () => {
|
||||
let runtime: any;
|
||||
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
|
||||
thtRunner: {
|
||||
sessionNew: async () => ({ id: "english-question", interaction_language: "en" }),
|
||||
searchPack: async () => {},
|
||||
},
|
||||
readiness: { ensure: async () => ({ ok: true }) },
|
||||
mgr: {
|
||||
get: () => undefined,
|
||||
createFor: (_id: string, options: any) => {
|
||||
runtime = options;
|
||||
return { bridge: { onClientEvent: () => {} } };
|
||||
},
|
||||
configure: async () => {}, start: () => {},
|
||||
},
|
||||
getSettings: () => ({ workspace: "default" }),
|
||||
});
|
||||
try {
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: {
|
||||
question: "How many patients were admitted last year?", interactionLanguage: "it",
|
||||
} });
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(runtime.interactionLanguage).toBe("en");
|
||||
} finally { await app.close(); }
|
||||
});
|
||||
|
||||
test("resume pins legacy interaction language using the resolved harness workspace", async () => {
|
||||
let pinnedWorkspace: string | undefined;
|
||||
let runtime: any;
|
||||
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
|
||||
thtRunner: {
|
||||
sessionShow: async () => ({ id: "legacy", status: "closed" }),
|
||||
ensureInteractionLanguage: async (_id: string, workspace: string) => {
|
||||
pinnedWorkspace = workspace;
|
||||
return { interaction_language: "it" };
|
||||
},
|
||||
reopenSession: async () => {},
|
||||
},
|
||||
readiness: { ensure: async () => ({ ok: true }) },
|
||||
mgr: {
|
||||
get: () => undefined,
|
||||
createFor: (_id: string, options: any) => {
|
||||
runtime = options;
|
||||
return { bridge: { onClientEvent: () => {} } };
|
||||
},
|
||||
configure: async () => {}, start: () => {},
|
||||
},
|
||||
getSettings: () => ({ workspace: "other-browser-workspace" }),
|
||||
});
|
||||
try {
|
||||
const response = await app.inject({ method: "POST", url: "/sessions/legacy/resume" });
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(pinnedWorkspace).toContain("/default.yaml");
|
||||
expect(runtime).toMatchObject({ interactionLanguage: "it", mode: "resume" });
|
||||
} finally { await app.close(); }
|
||||
});
|
||||
|
||||
test("resume retains persisted interaction language despite different browser settings", async () => {
|
||||
let options: any;
|
||||
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
|
||||
thtRunner: {
|
||||
sessionShow: async () => ({ id: "saved", status: "closed", interaction_language: "it" }),
|
||||
ensureInteractionLanguage: async () => { throw new Error("language is already pinned"); },
|
||||
reopenSession: async () => {},
|
||||
},
|
||||
readiness: { ensure: async () => ({ ok: true }) },
|
||||
mgr: {
|
||||
get: () => undefined,
|
||||
createFor: (_id: string, value: any) => {
|
||||
options = value;
|
||||
return { bridge: { onClientEvent: () => {} } };
|
||||
},
|
||||
configure: async () => {}, start: () => {},
|
||||
},
|
||||
getSettings: () => ({ workspace: "english-workspace", locale: "en" }),
|
||||
});
|
||||
try {
|
||||
const response = await app.inject({ method: "POST", url: "/sessions/saved/resume" });
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(options.interactionLanguage).toBe("it");
|
||||
} finally { await app.close(); }
|
||||
});
|
||||
|
||||
test("resume cannot start Pi if legacy interaction language cannot be persisted", async () => {
|
||||
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
|
||||
thtRunner: {
|
||||
sessionShow: async () => ({ id: "legacy", status: "closed" }),
|
||||
ensureInteractionLanguage: async () => { throw new Error("private storage details"); },
|
||||
reopenSession: async () => { throw new Error("must not reopen"); },
|
||||
},
|
||||
readiness: { ensure: async () => ({ ok: true }) },
|
||||
mgr: { createFor: () => { throw new Error("must not spawn"); } },
|
||||
getSettings: () => ({ workspace: "default" }),
|
||||
});
|
||||
try {
|
||||
const response = await app.inject({ method: "POST", url: "/sessions/legacy/resume" });
|
||||
expect(response.statusCode).toBe(503);
|
||||
expect(response.body).not.toContain("private storage details");
|
||||
} finally { await app.close(); }
|
||||
});
|
||||
|
||||
test("upstream requests without a principal fail before a Pi runtime can be created", async () => {
|
||||
let created = false;
|
||||
const app = buildApp(loadConfig({ AUTH_MODE: "upstream", THT_HARNESS_DIR: "../harness" }), {
|
||||
@@ -95,7 +249,7 @@ test("upstream requests without a principal fail before a Pi runtime can be crea
|
||||
thtRunner: {} as any,
|
||||
});
|
||||
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
|
||||
expect(response.statusCode).toBe(401);
|
||||
expect(created).toBe(false);
|
||||
@@ -133,7 +287,7 @@ test("maintenance rejects new and resumed session admission without interrupting
|
||||
});
|
||||
|
||||
const create = await app.inject({
|
||||
method: "POST", url: "/sessions", headers: aliceHeaders, payload: { question: "q" },
|
||||
method: "POST", url: "/sessions", headers: aliceHeaders, payload: { interactionLanguage: "en", question: "q" },
|
||||
});
|
||||
const resume = await app.inject({ method: "POST", url: "/sessions/open/resume", headers: aliceHeaders });
|
||||
|
||||
@@ -154,7 +308,7 @@ test("a durable maintenance marker initializes admission closed after backend re
|
||||
AUTH_MODE: "upstream", THT_HARNESS_DIR: "../harness", THT_MAINTENANCE_FILE: marker,
|
||||
}), { thtRunner: {} as any });
|
||||
const response = await app.inject({
|
||||
method: "POST", url: "/sessions", headers: aliceHeaders, payload: { question: "q" },
|
||||
method: "POST", url: "/sessions", headers: aliceHeaders, payload: { interactionLanguage: "en", question: "q" },
|
||||
});
|
||||
expect(response.statusCode).toBe(503);
|
||||
expect(response.json()).toMatchObject({ code: "maintenance" });
|
||||
@@ -492,7 +646,7 @@ test("new sessions are created through the authenticated principal, not a client
|
||||
|
||||
const response = await app.inject({
|
||||
method: "POST", url: "/sessions", headers: aliceHeaders,
|
||||
payload: { question: "q", owner: "mallory" },
|
||||
payload: { interactionLanguage: "en", question: "q", owner: "mallory" },
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
@@ -509,7 +663,7 @@ test("new sessions reject the client legacy workspace field unless local legacy
|
||||
});
|
||||
|
||||
const response = await app.inject({
|
||||
method: "POST", url: "/sessions", payload: { question: "q", workspace: "legacy" },
|
||||
method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q", workspace: "legacy" },
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(409);
|
||||
@@ -529,7 +683,7 @@ test("explicit local legacy mode permits the unpinned client workspace request",
|
||||
});
|
||||
|
||||
const response = await app.inject({
|
||||
method: "POST", url: "/sessions", payload: { question: "q", workspace: "legacy" },
|
||||
method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q", workspace: "legacy" },
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
@@ -567,7 +721,7 @@ test("creates a session from the active immutable workspace revision", async ()
|
||||
|
||||
await app.inject({
|
||||
method: "POST", url: "/sessions",
|
||||
payload: { question: "q", workspaceId: "psd-clinical", provider: "zai", model: "glm-5.2", thinking: "low" },
|
||||
payload: { interactionLanguage: "en", question: "q", workspaceId: "psd-clinical", provider: "zai", model: "glm-5.2", thinking: "low" },
|
||||
});
|
||||
|
||||
expect(sessionNew).toHaveBeenCalledWith(expect.objectContaining({
|
||||
@@ -611,7 +765,7 @@ test("hands one Catalog-backed runtime to both retrieval and Pi", async () => {
|
||||
const response = await app.inject({
|
||||
method: "POST",
|
||||
url: "/sessions",
|
||||
payload: { question: "Which users placed orders?", workspaceId: "default" },
|
||||
payload: { interactionLanguage: "en", question: "Which users placed orders?", workspaceId: "default" },
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
@@ -687,7 +841,7 @@ test("refuses core admission when the workspace preprocessing fingerprint is sta
|
||||
const response = await app.inject({
|
||||
method: "POST",
|
||||
url: "/sessions",
|
||||
payload: { question: "q", workspaceId: "default" },
|
||||
payload: { interactionLanguage: "en", question: "q", workspaceId: "default" },
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(409);
|
||||
@@ -739,7 +893,7 @@ test("rejects an SSH-only Catalog binding before persisting or starting a sessio
|
||||
} as any,
|
||||
});
|
||||
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
|
||||
expect(response.statusCode).toBe(409);
|
||||
expect(response.json()).toMatchObject({ code: "workspace_not_activatable" });
|
||||
@@ -779,7 +933,7 @@ test("hands a revision lease to retention only after the session manifest is dur
|
||||
workspaceRegistry: { acquireSessionRevision } as any,
|
||||
});
|
||||
|
||||
const request = app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const request = app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
expect(markPersisted).not.toHaveBeenCalled();
|
||||
expect(abort).not.toHaveBeenCalled();
|
||||
@@ -810,7 +964,7 @@ test("creates a session from the configured default workspace revision when work
|
||||
workspaceRegistry: registry as any,
|
||||
});
|
||||
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
|
||||
expect(registry.read).toHaveBeenCalledWith("psd-clinical");
|
||||
expect(sessionNew).toHaveBeenCalledWith(expect.objectContaining({
|
||||
@@ -896,7 +1050,7 @@ test("session lifecycle locates a B session when installation default is A", asy
|
||||
} as any,
|
||||
});
|
||||
|
||||
expect((await app.inject({ method: "POST", url: "/sessions", payload: {
|
||||
expect((await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en",
|
||||
question: "B question", workspaceId: "b-workspace", provider: "zai", model: "glm-5.2", thinking: "low",
|
||||
} })).statusCode).toBe(200);
|
||||
expect((await app.inject({ method: "GET", url: "/sessions" })).json()).toEqual([
|
||||
@@ -939,7 +1093,7 @@ test("POST /sessions uses the catalog default with workspace/thinking settings a
|
||||
],
|
||||
spawnFn: () => nodeSpawn("node", [FAKE, SCRIPT]) as any,
|
||||
});
|
||||
const created = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const created = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
expect(created.json()).toEqual({ id: "s1" });
|
||||
expect(sessionNewArg.workspaceConfigPath).toContain(`/snapshots/${"e".repeat(40)}/w.yaml`);
|
||||
expect(sessionNewArg.provider).toBe("zai");
|
||||
@@ -1000,11 +1154,11 @@ test("POST /sessions stops the user's previous open Pi runtime before creating a
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
|
||||
expect((await app.inject({ method: "POST", url: "/sessions", payload: { question: "one" } })).statusCode)
|
||||
expect((await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "one" } })).statusCode)
|
||||
.toBe(200);
|
||||
order.length = 0;
|
||||
|
||||
const second = await app.inject({ method: "POST", url: "/sessions", payload: { question: "two" } });
|
||||
const second = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "two" } });
|
||||
|
||||
expect(second.statusCode).toBe(200);
|
||||
expect(second.json()).toEqual({ id: "s2" });
|
||||
@@ -1025,7 +1179,7 @@ test("POST /sessions refuses to create a session when the local DWH precheck fai
|
||||
readiness: { ensure: async () => ({ ok: true }) } as any,
|
||||
getSettings: () => ({ workspace: "w" }) as any,
|
||||
});
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
expect(res.statusCode).toBe(503);
|
||||
expect(res.json()).toMatchObject({ code: "dwh_unreachable" });
|
||||
expect(pinged).toBe(1);
|
||||
@@ -1046,7 +1200,7 @@ test("POST /sessions proceeds past a passing DWH precheck", async () => {
|
||||
getSettings: () => ({ workspace: "w" }) as any,
|
||||
spawnFn: () => nodeSpawn("node", [FAKE, SCRIPT]) as any,
|
||||
});
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(pinged).toBe(1);
|
||||
expect(created).toBe(1);
|
||||
@@ -1065,7 +1219,7 @@ test("POST /sessions skips the DWH precheck when the flag is off (default)", asy
|
||||
getSettings: () => ({ workspace: "w" }) as any,
|
||||
spawnFn: () => nodeSpawn("node", [FAKE, SCRIPT]) as any,
|
||||
});
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(pinged).toBe(0); // probe never runs without the flag
|
||||
});
|
||||
@@ -1099,7 +1253,7 @@ test("POST /sessions configura Pi con il thinking globale selezionato", async ()
|
||||
],
|
||||
});
|
||||
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
|
||||
expect(configured.thinking).toBe("high");
|
||||
@@ -1427,7 +1581,7 @@ test("resuming a different session stops the user's previous Pi runtime", async
|
||||
readiness: { ensure: async () => ({ ok: true }) } as any,
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
expect((await app.inject({ method: "POST", url: "/sessions", payload: { question: "one" } })).statusCode)
|
||||
expect((await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "one" } })).statusCode)
|
||||
.toBe(200);
|
||||
|
||||
const resumed = await app.inject({ method: "POST", url: "/sessions/s2/resume" });
|
||||
@@ -1815,13 +1969,13 @@ test.each([
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "old" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "old" } });
|
||||
if (lifecycle === "close") {
|
||||
await app.inject({ method: "POST", url: "/sessions/s1/close" });
|
||||
await app.inject({ method: "POST", url: "/sessions/s1/resume" });
|
||||
} else {
|
||||
await app.inject({ method: "DELETE", url: "/sessions/s1" });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "replacement" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "replacement" } });
|
||||
}
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
expect(current).toBe(replacement);
|
||||
@@ -1885,7 +2039,7 @@ test.each(["resolve", "reject"] as const)(
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "old" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "old" } });
|
||||
await app.inject({ method: "DELETE", url: "/sessions/s1" });
|
||||
published.length = 0;
|
||||
|
||||
@@ -2077,7 +2231,7 @@ test("Close suppresses a bootstrap that settles while close persistence is pendi
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
const closeResponse = app.inject({ method: "POST", url: "/sessions/s1/close" });
|
||||
await closeStarted;
|
||||
published.length = 0;
|
||||
@@ -2151,7 +2305,7 @@ test("bootstrap failure persists once and keeps Resume serialized behind that pe
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
oldConfigure.reject(new Error("configure failed"));
|
||||
await failureStarted;
|
||||
const resumeResponse = app.inject({ method: "POST", url: "/sessions/s1/resume" })
|
||||
@@ -2274,7 +2428,7 @@ test("a replaced runtime cannot publish or fail the newly resumed session", asyn
|
||||
readiness: { ensure: async () => ({ ok: true }) } as any,
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
oldBridge.setState("idle");
|
||||
|
||||
@@ -2334,7 +2488,7 @@ test("a deleted runtime cannot repopulate or fail the forgotten session", async
|
||||
readiness: { ensure: async () => ({ ok: true }) } as any,
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
|
||||
const response = await app.inject({ method: "DELETE", url: "/sessions/s1" });
|
||||
@@ -2379,7 +2533,7 @@ test("an unexpectedly exited runtime publishes its terminal sequence then releas
|
||||
readiness: { ensure: async () => ({ ok: true }) } as any,
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
published.length = 0;
|
||||
|
||||
@@ -2430,7 +2584,7 @@ test("agent_end releases the Pi runtime after the session was finalized", async
|
||||
readiness: { ensure: async () => ({ ok: true }) } as any,
|
||||
getSettings: () => ({ workspace: "local" }) as any,
|
||||
});
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
|
||||
bridge.emitClientEvent({ type: "system_event", event: "agent_end" });
|
||||
@@ -2502,7 +2656,7 @@ test("POST /sessions/:id/response senza gate pendente risponde 409 (risposta sta
|
||||
getSettings: () => ({ workspace: "w" }),
|
||||
spawnFn: () => nodeSpawn("node", [FAKE, SCRIPT]) as any,
|
||||
});
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
// The fake Pi never emitted a ui_request: the bridge has no pending descriptor, so a
|
||||
// response (stale UI, double submit) must be rejected instead of forwarded to Pi.
|
||||
const res = await app.inject({ method: "POST", url: "/sessions/s1/response",
|
||||
@@ -2643,7 +2797,7 @@ test("POST /sessions readiness failure returns one fixed public message without
|
||||
getSettings: () => ({ workspace: "psd" }) as any,
|
||||
spawnFn: () => nodeSpawn("node", [FAKE, SCRIPT]) as any,
|
||||
});
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
expect(res.statusCode).toBe(503);
|
||||
expect(res.json()).toEqual({
|
||||
error: "Session services are not ready. Check configuration and connectivity, then try again.",
|
||||
@@ -2664,7 +2818,7 @@ test.each(["semantic_index_incompatible", "workspace_not_activatable"] as const)
|
||||
});
|
||||
|
||||
const response = await app.inject({
|
||||
method: "POST", url: "/sessions", payload: { question: "q" },
|
||||
method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" },
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(503);
|
||||
@@ -2687,7 +2841,7 @@ test("POST /sessions returns storage 503 before creating a Pi runtime when sessi
|
||||
mgr: { createFor: () => { piCreated = true; throw new Error("must not spawn"); } } as any,
|
||||
});
|
||||
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
|
||||
expect(response.statusCode).toBe(503);
|
||||
expect(response.json()).toEqual({ error: "session storage is unavailable" });
|
||||
@@ -2707,7 +2861,7 @@ test("POST /sessions proceeds when ollamaEnsure succeeds", async () => {
|
||||
getSettings: () => ({ workspace: "psd" }) as any,
|
||||
spawnFn: () => nodeSpawn("node", [FAKE, SCRIPT]) as any,
|
||||
});
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
expect(res.json()).toEqual({ id: "s1" });
|
||||
expect(qdrantEnsure).toHaveBeenCalledWith(operationalWorkspace("psd"), 60, "self_heal");
|
||||
expect(ensureWs).toContain(`/snapshots/${"e".repeat(40)}/psd.yaml`);
|
||||
@@ -2740,7 +2894,7 @@ test("POST /sessions rejects a stale requested model without silently using the
|
||||
const res = await app.inject({
|
||||
method: "POST",
|
||||
url: "/sessions",
|
||||
payload: { question: "q", provider: "deepseek", model: "deepseek-v4-pro" },
|
||||
payload: { interactionLanguage: "en", question: "q", provider: "deepseek", model: "deepseek-v4-pro" },
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(503);
|
||||
@@ -2775,7 +2929,7 @@ test("POST /sessions marks a persisted session failed when runtime construction
|
||||
],
|
||||
});
|
||||
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
|
||||
expect(res.statusCode).toBe(503);
|
||||
expect(res.json()).toEqual({
|
||||
@@ -2868,7 +3022,7 @@ test.each([
|
||||
|
||||
try {
|
||||
const response = flow === "new"
|
||||
? await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } })
|
||||
? await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } })
|
||||
: await app.inject({ method: "POST", url: `/sessions/${sessionId}/resume` });
|
||||
const logs = consoleError.mock.calls.flat().map(String).join(" ");
|
||||
|
||||
@@ -2974,7 +3128,7 @@ test("POST /sessions returns after bridge attachment but starts only after retri
|
||||
getSettings: () => ({ workspace: "psd" }) as any,
|
||||
});
|
||||
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const res = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
expect(res.json()).toEqual({ id: "s-early" });
|
||||
expect(bridgeAttached).toBe(true);
|
||||
expect(started).toBe(false);
|
||||
@@ -3021,7 +3175,7 @@ test("POST /sessions bootstrap failure emits only a fixed recovery message", asy
|
||||
const response = await app.inject({
|
||||
method: "POST",
|
||||
url: "/sessions",
|
||||
payload: { question: "q" },
|
||||
payload: { interactionLanguage: "en", question: "q" },
|
||||
});
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
|
||||
@@ -3117,7 +3271,7 @@ test.each([
|
||||
})),
|
||||
} as any,
|
||||
});
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { interactionLanguage: "en", question: "q" } });
|
||||
|
||||
expect(response.statusCode).toBe(expectedStatus);
|
||||
expect(ensure).toHaveBeenCalledTimes(reachesReadiness ? 1 : 0);
|
||||
|
||||
@@ -34,6 +34,19 @@ test("sessionNew parses id from JSON", async () => {
|
||||
expect(await r.sessionNew({ question: "q" })).toEqual({ id: "2026-06-27-100000-x" });
|
||||
});
|
||||
|
||||
test("session language uses public per-command CLI flags and the selected config", async () => {
|
||||
const runner = new ThtRunner({ thtBin: "tht", harnessDir: "/h", configPath: "config/tht.yaml" });
|
||||
(spawn as any).mockClear();
|
||||
await runner.sessionNew({ question: "Pazienti", interactionLanguage: "en" });
|
||||
expect((spawn as any).mock.calls[0][1]).toEqual([
|
||||
"session", "new", "Pazienti", "--interaction-language", "en", "--json", "-c", "config/tht.yaml",
|
||||
]);
|
||||
await runner.ensureInteractionLanguage("s1");
|
||||
expect((spawn as any).mock.calls[1][1]).toEqual([
|
||||
"session", "ensure-interaction-language", "s1", "--json", "-c", "config/tht.yaml",
|
||||
]);
|
||||
});
|
||||
|
||||
test("searchPack persists retrieval context with session and workspace", async () => {
|
||||
const calls: any[] = [];
|
||||
const r = new ThtRunner({ thtBin: "tht", harnessDir: "/h", configPath: "config/tht.yaml" });
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Local-only rollback to the full-shell frontend before visual integration.
|
||||
# Apply after local installation profiles, with --no-build and --no-deps.
|
||||
services:
|
||||
frontend:
|
||||
image: thothii-frontend:before-visual-shell-merge-20260913
|
||||
@@ -2,6 +2,10 @@
|
||||
# Replace every absolute path before using this as an advanced reference.
|
||||
schemaVersion: 2
|
||||
profile: local
|
||||
# Mac standalone example; the Omics server requires embedded/upstream separately.
|
||||
shell:
|
||||
mode: full
|
||||
defaultLocale: en
|
||||
projectDirectory: "<abs>/projects/ThothII"
|
||||
envFile: "<abs>/projects/ThothII/deploy/psd/operator.env"
|
||||
workspaceRepository:
|
||||
|
||||
@@ -8,6 +8,11 @@ cp deploy/secrets/thothii.secrets.example deploy/secrets/thothii.secrets
|
||||
chmod 600 deploy/secrets/thothii.secrets
|
||||
```
|
||||
|
||||
For a normal local installation, `tht setup --complete` creates the active bundle at
|
||||
`deploy/local/secrets/thothii.secrets` and creates the two Catalog password files beside it. The
|
||||
generated `deploy/local/operator.env` contains only absolute paths to those files; never copy
|
||||
secret values into `operator.env`.
|
||||
|
||||
The file uses strict `KEY=VALUE` lines (comments and blank lines are allowed). The supported
|
||||
installation keys are `THT_MODEL_API_KEY`, `THT_DWH_API_KEY`, `THT_CA`, `THT_SSL_CA`,
|
||||
`THT_OIDC_CLIENT_SECRET`, and `THT_AUTHENTIK_API_TOKEN`. Installation Model Catalog providers may
|
||||
@@ -29,6 +34,11 @@ Session and metadata-generation runtimes read only the provider key named by
|
||||
credential reference, not their execution lifecycle. Pi-owned authentication remains available only
|
||||
to session-only built-in providers through `authentication.mode: pi_auth`.
|
||||
|
||||
Workspace database credentials are intentionally not part of this global bundle. Configure each
|
||||
workspace's database binding, password/token, tunnel key and CA in Database Management; the
|
||||
installation stores those values in its encrypted workspace secret store. The workspace Git
|
||||
repository may declare database identity and Evidence, but must never contain these credentials.
|
||||
|
||||
Do not add vector or embedding endpoint credentials to the bundle. Active operator manuals use
|
||||
internal Qdrant and Ollama services, so vector/embedding runtime endpoint secrets are not part of
|
||||
the supported installation contract.
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
test "$(cat /usr/share/nginx/html/config.js)" = 'window.__THOTHII_CONFIG__ = {};'
|
||||
# The generic image contains an empty fallback; installed containers mount the generated
|
||||
# public projection over it. An optional path lets host projection tests use this same check.
|
||||
config_file=${1:-/usr/share/nginx/html/config.js}
|
||||
test -f "$config_file" && test -r "$config_file"
|
||||
config=$(tr -d '[:space:]' < "$config_file")
|
||||
case "$config" in
|
||||
'window.__THOTHII_CONFIG__={};')
|
||||
test -z "${THT_FRONTEND_CONFIG_REVISION:-}"
|
||||
;;
|
||||
*)
|
||||
# Installation Load validates BCP47 syntax. Here check only the public payload shape;
|
||||
# catalog availability and fallback belong to the frontend, not the generic image.
|
||||
locale='[A-Za-z][A-Za-z0-9]*(-[A-Za-z0-9]+)*'
|
||||
full="\"mode\":\"full\",\"defaultLocale\":\"$locale\""
|
||||
embedded="\"mode\":\"embedded\",\"defaultLocale\":\"$locale\",\"adapter\":\"omics-portal\""
|
||||
if ! printf '%s\n' "$config" | LC_ALL=C grep -Eq "^window\.__THOTHII_CONFIG__=\{\"backendBaseUrl\":\"/api\",\"shell\":\{($full|$embedded)\}\};$"; then
|
||||
echo "Invalid frontend public runtime configuration" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
printf '%s\n' "frontend runtime config smoke: ok"
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# ADR 0021 — Shell separati e adapter sostituibile per il portale
|
||||
|
||||
- Stato: accettato
|
||||
- Data: 2026-09-13
|
||||
|
||||
## Decisione
|
||||
|
||||
ThothII espone due modalità di installazione, selezionate da `shell.mode`:
|
||||
|
||||
- `embedded` (default): ThothII è ospitato da Omics Portal. Non renderizza alcun header e
|
||||
riceve dal portale lingua, tema e fullscreen. L'accesso resta verificato dal server.
|
||||
- `full`: ThothII è autonomo. Renderizza il proprio header, con selettore lingua, tema,
|
||||
fullscreen e nome utente. Il click sul nome apre il logout. Non mostra mai la rotellina o
|
||||
altri comandi amministrativi del portale. Mantiene un rail vuoto a sinistra di almeno 20 px.
|
||||
|
||||
Il fatto che la shell sia `full` è distinto dallo stato `fullscreen`: la prima decide quale
|
||||
contenitore viene renderizzato, il secondo indica se è attiva la Fullscreen API del browser.
|
||||
L'icona passa da “entra in fullscreen” a “torna alla modalità normale”; anche `Esc` aggiorna lo
|
||||
stato visualizzato.
|
||||
|
||||
La configurazione installata resta semplice e retrocompatibile. Sul Mac di sviluppo il profilo
|
||||
locale userà:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: full
|
||||
defaultLocale: en
|
||||
```
|
||||
|
||||
Il deploy sul server userà invece:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: embedded
|
||||
adapter: omics-portal
|
||||
```
|
||||
|
||||
`defaultLocale` indica la lingua iniziale della shell full; in embedded la fonte autorevole resta
|
||||
il portale.
|
||||
|
||||
L'adapter è l'unico confine tra ThothII e il portale. La sua interfaccia pubblica è volutamente
|
||||
profonda e minima: consegna solo snapshot dello stato, senza esporre comandi, token, identità o
|
||||
dettagli di trasporto.
|
||||
|
||||
```ts
|
||||
export type HostShellState = {
|
||||
locale: string; // BCP-47, inizialmente it/en
|
||||
theme: "light" | "dark";
|
||||
fullscreen: boolean;
|
||||
};
|
||||
|
||||
export interface PortalAdapter {
|
||||
subscribe(
|
||||
onState: (state: HostShellState) => void,
|
||||
onError: (error: Error) => void,
|
||||
): () => void;
|
||||
}
|
||||
```
|
||||
|
||||
`OmicsPortalAdapter` è l'implementazione corrente. Un adapter per un altro portale potrà
|
||||
sostituirlo senza modificare shell, i18n o workflow. In `full` l'adapter non viene istanziato:
|
||||
lo stato è gestito internamente dalla shell.
|
||||
|
||||
Per l'integrazione oggi operativa, che monta la SPA direttamente nel DOM di Omics Portal,
|
||||
l'adapter legge la lingua effettiva dal selettore Omics, osserva l'attributo del tema e ascolta
|
||||
il fullscreen del documento. Selettori e osservatori restano privati dell'implementazione Omics.
|
||||
La lingua segue il normale ricaricamento Django; tema e fullscreen cambiano nella pagina aperta.
|
||||
La revisione approvata del 2026-09-13 elimina il precedente handshake a eventi: non servono
|
||||
messaggi personalizzati, versioni di trasporto o timeout di avvio. Un futuro adapter potrà usare
|
||||
un diverso trasporto senza modificare l'interfaccia applicativa.
|
||||
|
||||
Se `shell` o l'adapter embedded sono omessi, si usa `embedded` con `omics-portal`. Questo default
|
||||
supporta il documento Omics esistente; nomi adapter sconosciuti o dati host mancanti producono
|
||||
un errore esplicito, senza attivare la shell full.
|
||||
|
||||
## Confini che restano invariati
|
||||
|
||||
L'identità e l'autorizzazione del backend non vengono ricostruite nel browser. In embedded,
|
||||
Omics Portal continua a gestire login e logout e la catena server-side `auth_request` continua a
|
||||
fornire i principal header già previsti. Lo stato UI non dichiara l'utente autenticato: il modulo
|
||||
di accesso usa la verifica backend esistente anche alla riconnessione e al ritorno alla pagina.
|
||||
Un rifiuto su una singola operazione non equivale automaticamente alla perdita dell'accesso.
|
||||
|
||||
La lingua UI e la lingua di interazione con il modello restano separate dalla lingua del
|
||||
workspace; il relativo contratto è in [ADR 0022](0022-separate-ui-locale-from-session-interaction-language.md).
|
||||
|
||||
## Alternative scartate
|
||||
|
||||
- Duplicare l'header di Omics in embedded: crea due fonti di stato e incompatibilità visive.
|
||||
- Spargere controlli `if embedded/full` nei componenti: lega ogni pagina al portale.
|
||||
- Trasmettere utente o token nel bridge: aumenta superficie e accoppia UI e autenticazione.
|
||||
- Introdurre un protocollo completo request/response: non aggiunge funzionalità richiesta.
|
||||
- Usare `profile` per distinguere le shell: `profile` descrive la topologia dell'installazione,
|
||||
non la sua presentazione.
|
||||
|
||||
## Conseguenze
|
||||
|
||||
La soluzione richiede un adapter nel frontend che osserva il documento condiviso e mantiene la
|
||||
logica di shell locale a ThothII. Il backend non necessita di un nuovo protocollo di autenticazione
|
||||
o di una nuova sessione browser. Un nuovo portale deve soddisfare anche il contratto server di
|
||||
identità fidata: la sola sostituzione della classe UI non sostituisce quel contratto.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Separate UI locale from session interaction language
|
||||
|
||||
status: accepted
|
||||
|
||||
ThothII distinguishes three language concepts:
|
||||
|
||||
- `workspace.language` remains the language of workspace-owned documents, descriptions and Evidence;
|
||||
- `ui_locale` controls deterministic ThothII chrome such as labels, form help, placeholders, errors,
|
||||
accessibility text and review-widget chrome;
|
||||
- `interaction_language` is persisted in a session and controls model-generated questions,
|
||||
explanations and reviewer proposals.
|
||||
|
||||
The initial locale catalog supports Italian and English and uses extensible BCP-47 language tags.
|
||||
Missing deterministic translations fall back to English. The selected UI locale supplies the default
|
||||
interaction language when a new session is created. A resumed session always uses its persisted
|
||||
interaction language; changing the host or full-shell UI locale must not silently rewrite an existing
|
||||
session or make its model output switch language mid-workflow.
|
||||
|
||||
The distinction is required because the current workspace contract already uses `language` for
|
||||
content and the PSD workspace is Italian. Reusing that field for a browser preference would make a
|
||||
visual choice mutate domain content semantics. The model receives the session interaction language
|
||||
through the session/Pi workflow context. SQL, identifiers, database values and other technical
|
||||
artifacts remain governed by their existing contracts and are not translated as UI strings.
|
||||
|
||||
In `full`, the local shell owns `ui_locale` and supplies it when starting a new session. In
|
||||
`embedded`, the host adapter is authoritative for `ui_locale`; ThothII applies host changes to
|
||||
deterministic UI immediately while preserving the interaction language of any active session.
|
||||
|
||||
We considered using only `workspace.language`, using only a global browser locale, and translating
|
||||
the model output after generation. The first conflates domain content with UI preference; the second
|
||||
cannot preserve a session's language or follow the host portal; and the third would be unsafe for
|
||||
structured reviewer decisions and would not control the model's reasoning or proposal language.
|
||||
|
||||
## Considered Options
|
||||
|
||||
- One mutable `language` field for workspace, UI and session was rejected because the fields have
|
||||
different owners and lifecycles.
|
||||
- Client-only translation of reviewer choices was rejected because choices can be generated by the
|
||||
model and must be requested in the intended language.
|
||||
- An English-only deterministic chrome was rejected because embedded and full installations must
|
||||
follow the selected host/user language.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Session creation and the persisted manifest gain an explicit interaction-language value.
|
||||
- Legacy manifests without that value use the workspace language, pinned idempotently on first
|
||||
resume; the browser locale must not determine this compatibility value.
|
||||
- Resume must read that value from the manifest and must not accept a new locale as an override.
|
||||
- The workflow prompt contract and deterministic reviewer-widget builders need a locale-aware input.
|
||||
- Frontend strings need a catalog and stable keys; backend events should expose stable codes where
|
||||
the frontend is responsible for localization.
|
||||
@@ -0,0 +1,135 @@
|
||||
# Rendering full ed embedded
|
||||
|
||||
ThothII ha una sola applicazione React, una sola build Vite e gli stessi servizi
|
||||
backend. «Doppio rendering» significa due modi di ospitare quella applicazione,
|
||||
non due versioni delle pagine e non rendering React sul server. Django renderizza
|
||||
il contenitore Omics; React renderizza ThothII nel browser, dentro `#root`.
|
||||
|
||||
## Tre decisioni indipendenti
|
||||
|
||||
| Decisione | Configurazione | Effetto |
|
||||
| --- | --- | --- |
|
||||
| Distribuzione | `profile: local` oppure `server` | Compose, percorsi e vincoli operativi |
|
||||
| Presentazione | `shell.mode: full` oppure `embedded` | Proprietario di header e preferenze |
|
||||
| Autenticazione | `auth.yaml` local/OIDC oppure `AUTH_MODE=upstream` | Chi verifica l'identità, come arriva al backend |
|
||||
|
||||
Il Mac usa **full + local**, con lingua iniziale inglese. L'integrazione Omics
|
||||
usa **embedded + upstream**, con accesso già verificato dal portale. Un server
|
||||
autonomo può usare **full + oidc**. Cambiare `shell.mode` non abilita un metodo
|
||||
di autenticazione e non modifica permessi o proprietari delle sessioni.
|
||||
|
||||
Full con upstream può visualizzare un'identità già verificata dal proxy, ma non
|
||||
ha un logout ThothII disponibile: non è il profilo autonomo con login/logout.
|
||||
Embedded non avvia login locale o OIDC anche se il backend è configurato così;
|
||||
questa combinazione non realizza il login unico Omics e non va usata come fallback.
|
||||
|
||||
## Composizione comune
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
CONFIG["config.js pubblico"] --> SHELL["ShellProvider"]
|
||||
FULL["Preferenze full nel browser"] --> SHELL
|
||||
HOST["Documento Omics"] --> ADAPTER["OmicsPortalAdapter: solo presentazione"]
|
||||
ADAPTER --> SHELL
|
||||
SHELL --> GATE["AuthGate: verifica GET /me"]
|
||||
GATE --> APP["AppShell: stesse pagine, sessioni e amministrazione"]
|
||||
AUTH["Backend: cookie locale/OIDC o identità upstream"] --> GATE
|
||||
```
|
||||
|
||||
`ShellProvider` risolve la configurazione, applica lingua/tema e monta i contenuti
|
||||
solo dopo uno snapshot host valido in embedded. `AuthGate` verifica l'accesso;
|
||||
`AppShell` e le pagine non devono leggere selettori o eventi specifici di Omics.
|
||||
Il cambio utente smonta lo stato applicativo della precedente identità.
|
||||
|
||||
## Full
|
||||
|
||||
- Header ThothII rosso Omics `#CB333B` in entrambi i temi; logo interamente chiaro.
|
||||
- Selettore EN/IT, tema light/dark, fullscreen e nome verificato dell'utente.
|
||||
- Menu del nome con logout soltanto per local/OIDC; nessuna rotellina admin.
|
||||
L'amministrazione resta nella navigazione applicativa, secondo i permessi.
|
||||
- Margine sinistro vuoto e simmetrico al destro: `max(20px, 1.5rem)`, normalmente
|
||||
24px con radice a 16px. Non è una seconda sidebar di navigazione.
|
||||
- Lingua e tema ricordati sullo stesso origin in `localStorage`, nelle chiavi
|
||||
`thothii:shell:locale` e `thothii:shell:theme`. Non sono preferenze server per
|
||||
utente. In assenza di preferenze: `defaultLocale` e tema light.
|
||||
- Fullscreen usa `document.documentElement.requestFullscreen()` e
|
||||
`document.exitFullscreen()`: nasconde il contorno del browser dove supportato.
|
||||
L'icona cambia sullo stato reale, anche dopo Esc; un rifiuto mostra un errore.
|
||||
Non è un semplice ingrandimento CSS e non scatta automaticamente all'accesso.
|
||||
|
||||
## Embedded
|
||||
|
||||
- Nessun header ThothII, selettore lingua, toggle tema, login o logout autonomo.
|
||||
I controlli rimangono nell'header generale Omics.
|
||||
- React è nello stesso documento della pagina `/kokoro/datamart-builder/`, non
|
||||
in un iframe. Non serve `postMessage` né un secondo protocollo di sessione.
|
||||
- L'adapter legge la lingua Django già confermata, osserva il tema del documento
|
||||
e ascolta il fullscreen reale. Le azioni rimangono di proprietà del portale.
|
||||
- Un contesto Omics mancante o invalido mostra un errore d'integrazione; non
|
||||
passa silenziosamente a full e non offre un secondo login.
|
||||
- Il portale assegna l'altezza disponibile sotto il proprio header: catena flex
|
||||
con `min-height: 0`, root contenuto e altezza applicativa vincolata al contenitore.
|
||||
Il contratto ThothII espone `--thoth-app-height` (fallback `100dvh`); verificare
|
||||
il contenitore reale, non presumere che l'intera viewport appartenga a React.
|
||||
Il template Omics mantiene inoltre i suoi override di compatibilità.
|
||||
|
||||
Il reset CSS è limitato al mount React e ai popup dell'applicazione, senza
|
||||
richiedere CSS `@scope`. I token e i popup seguono il tema applicativo. Questo
|
||||
non rende indipendenti fogli di stile arbitrari caricati dal portale: la verifica
|
||||
del documento condiviso rimane necessaria a ogni integrazione.
|
||||
|
||||
## Caricamento e configurazione pubblica
|
||||
|
||||
Il descrittore installato è la sorgente di verità. Il CLI genera
|
||||
`generated/frontend/config.js` e il suo mount di sola lettura nella proiezione
|
||||
`generated/compose.models.yaml`. Il file pubblico contiene solo `backendBaseUrl`
|
||||
e `shell`, mai identità, token, password o percorsi host. Va caricato **prima** del
|
||||
modulo React e servito senza cache. Nessuna build separata è richiesta per
|
||||
cambiare modalità; occorre rigenerare e applicare i mount tramite il lifecycle.
|
||||
|
||||
L'ordine Omics è: config pubblico → override del solo prefisso API → asset dal
|
||||
manifest Vite. L'override deve conservare `shell`; l'adapter non configura il proxy.
|
||||
Il default completo di shell omessa è embedded/en/omics-portal. Il CLI normalizza
|
||||
anche singoli campi omessi; un oggetto `shell` scritto manualmente nel browser
|
||||
deve invece contenere `mode` e `defaultLocale`, altrimenti viene rifiutato.
|
||||
|
||||
## Lingua, continuità e dati
|
||||
|
||||
La lingua UI traduce il testo dell'applicazione, non i contenuti di dominio.
|
||||
Alla creazione, la lingua UI viene acquisita come `interactionLanguage` di ripiego.
|
||||
Il CLI riconosce la lingua della domanda originale e salva `interaction_language`
|
||||
nel manifest; usa il ripiego solo per input troppo brevi, ambigui o composti da codice.
|
||||
Questa lingua governa domande, spiegazioni, scelte e controlli HITL. Il gate la
|
||||
include nei descrittori e il frontend la applica al sottoalbero dei widget,
|
||||
senza cambiare la lingua della navigazione.
|
||||
Alla ripresa vale la lingua salvata, non l'ultima scelta dell'header. Per i manifest
|
||||
precedenti senza campo viene riconosciuta e fissata la lingua della domanda,
|
||||
con la lingua workspace disponibile alla prima ripresa come ripiego.
|
||||
|
||||
Il cambio lingua Omics invia il form Django e ricarica la pagina. ThothII conserva
|
||||
solo l'ID della selezione in `sessionStorage`, separato per pathname, issuer e
|
||||
subject. Riapre i documenti, non avvia una generazione. Bozze non inviate e modifiche
|
||||
non salvate richiedono conferma prima della navigazione; non sono una trascrizione
|
||||
salvata. La ripresa operativa resta esplicita.
|
||||
|
||||
## Punti di implementazione e manutenzione
|
||||
|
||||
| Sorgente | Responsabilità |
|
||||
| --- | --- |
|
||||
| `tools/tht/internal/config/shell.go` | Normalizzazione e validazione del descrittore |
|
||||
| `tools/tht/internal/modelprojection/projection.go` | Config pubblico e mount generati |
|
||||
| `frontend/src/api/runtime-config.ts` | Validazione browser e prefisso API same-origin |
|
||||
| `frontend/src/shell/host/ShellProvider.tsx` | Composizione, preferenze e tema |
|
||||
| `frontend/src/shell/host/FullHeader.tsx` | Controlli solo full |
|
||||
| `frontend/src/shell/host/OmicsPortalAdapter.ts` | Conoscenza del documento Omics |
|
||||
| `frontend/src/auth/AuthGate.tsx` | Accesso e ricontrolli al ritorno alla pagina |
|
||||
| `backend/src/auth/auth.ts` e `principal.ts` | Verifica server dell'identità |
|
||||
|
||||
Per un altro portale servono un'implementazione del
|
||||
[PortalAdapter](../contracts/portal-shell-adapter-v1.md), la sua registrazione nei
|
||||
validatori CLI/browser e nel punto di composizione, oltre al
|
||||
[contratto di autenticazione server](../install/authentication-upstream.md).
|
||||
Il nome di una classe non è un plugin caricabile dinamicamente da YAML.
|
||||
|
||||
Procedure: [configurazione e deploy](../operations/shell-and-localization.md),
|
||||
[autenticazione](authentication.md), [accettazione](../testing/authentication-manual-acceptance.md).
|
||||
@@ -1,18 +1,27 @@
|
||||
# Authentication architecture
|
||||
|
||||
ThothII has two production authentication modes: `local` and generic `oidc`. The host operator
|
||||
surface is one CLI, `tht`; there is no separate authentication executable. The backend owns
|
||||
opaque browser sessions and authorization, while `tht` owns protected configuration and local-user
|
||||
files.
|
||||
ThothII supports `local` and generic `oidc` through protected `auth.yaml`, plus
|
||||
the trusted-proxy `upstream` path used by Omics. The host operator surface is
|
||||
one CLI, `tht`; there is no separate authentication executable. The backend owns
|
||||
authorization in all paths and opaque browser sessions only in local/OIDC.
|
||||
`tht` owns protected local/OIDC configuration and local-user files; upstream
|
||||
identity is supplied per request by the authenticated server proxy.
|
||||
|
||||
Presentation is separate: [full/embedded rendering](application-shell.md) does
|
||||
not select authentication. The Mac uses full/local; Omics uses embedded/upstream;
|
||||
a standalone server can use full/OIDC. Do not configure a second ThothII OIDC
|
||||
login simply because Omics itself authenticates users through Authentik.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
BROWSER["Browser"] --> BOUNDARY["Authentication boundary"]
|
||||
BOUNDARY --> LOCAL["Local users\nArgon2id hashes"]
|
||||
BOUNDARY --> OIDC["OIDC provider\nAuthorization Code PKCE"]
|
||||
BOUNDARY --> UPSTREAM["Trusted proxy\nVerified portal session"]
|
||||
OIDC --> GROUPS["Groups claim\nexact mapping"]
|
||||
LOCAL --> PRINCIPAL["Thoth principal"]
|
||||
GROUPS --> PRINCIPAL
|
||||
UPSTREAM --> PRINCIPAL
|
||||
PRINCIPAL --> ROLES["Roles"]
|
||||
ROLES --> PERMISSIONS["Permissions"]
|
||||
PERMISSIONS --> ROUTES["Protected routes"]
|
||||
@@ -21,6 +30,13 @@ flowchart TB
|
||||
|
||||
## Configuration and trust boundaries
|
||||
|
||||
The following protected-file configuration applies to local/OIDC. Upstream uses
|
||||
`AUTH_MODE=upstream` without a mounted `auth.yaml` or authentication runtime
|
||||
projection. The backend refuses both authorities together. `AUTH_MODE=none`
|
||||
and `mock` are development/test modes, not production fallbacks. The exact
|
||||
upstream setup, header contract, proxy hops and origin checks are in the
|
||||
[server integration guide](../install/authentication-upstream.md).
|
||||
|
||||
The installation descriptor points to an operator-controlled authentication directory. It contains
|
||||
non-secret `auth.yaml` and, for local mode, `users.yaml`. POSIX installations use a private
|
||||
directory and owner-only regular files; Windows uses equivalent owner-only ACLs. Secret values are
|
||||
@@ -49,6 +65,10 @@ Authentik is the first certified group-catalog adapter, not a special browser lo
|
||||
|
||||
## Group authorization
|
||||
|
||||
This section describes **ThothII's direct OIDC login**, not the embedded Omics
|
||||
path. Omics checks its own capability and administrator status and supplies
|
||||
normalized identity headers; ThothII does not repeat the OIDC groups exchange.
|
||||
|
||||
OIDC must return a direct, non-empty `groups` claim whose value is a JSON array of strings.
|
||||
Missing, malformed, indirect, or overage-style claims fail closed. The browser callback returns
|
||||
HTTP 401 with the generic code `oidc_callback_failed`; it does not expose the internal reason.
|
||||
@@ -100,6 +120,10 @@ prerequisite fails.
|
||||
|
||||
## Browser sessions
|
||||
|
||||
This section applies only to **local and direct OIDC**. Upstream reuses the
|
||||
portal's authenticated session at the proxy boundary, not a ThothII cookie;
|
||||
its `/me` response has `session: null` and `csrfToken: null`.
|
||||
|
||||
The browser receives only an opaque `HttpOnly`, `SameSite=Lax` cookie named `thothii_session`.
|
||||
State-changing cookie requests require the in-memory CSRF token, same-origin `Origin`, and Fetch
|
||||
Metadata checks when present. The frontend never stores bearer tokens or session secrets in Web
|
||||
@@ -116,5 +140,20 @@ affected sessions. Authentication configuration revision changes invalidate all
|
||||
reload. Logout deletes the server record. Backup restore excludes active sessions and OIDC state,
|
||||
recreates empty private auth-state directories, and therefore forces reauthentication.
|
||||
|
||||
Full local/OIDC logout calls `POST /auth/logout`, revokes the server session and
|
||||
clears its cookie. It does not call the identity provider's global logout. If the
|
||||
provider still has an SSO session, the next OIDC login can complete without
|
||||
another password prompt. Embedded has no ThothII logout control: use the portal.
|
||||
|
||||
## Access revalidation
|
||||
|
||||
The frontend treats `/me` as the access authority. In embedded it does not fetch
|
||||
`/auth/config` or offer local/OIDC login. On focus, pageshow, visibility return
|
||||
and event-stream reconnection it rechecks access. A 401/403 from this probe clears
|
||||
protected state; a 403 on one operation is not automatically an app-wide logout.
|
||||
Neither the DOM adapter nor the proxy's initial SSE check guarantees instantaneous
|
||||
revocation of streams already open in other tabs.
|
||||
|
||||
See the [local guide](../install/authentication-local.md), [generic OIDC guide](../install/authentication-oidc.md),
|
||||
and [Authentik guide](../install/authentik.md) for operator procedures.
|
||||
[Authentik guide](../install/authentik.md), [upstream integration](../install/authentication-upstream.md),
|
||||
and [manual acceptance matrix](../testing/authentication-manual-acceptance.md).
|
||||
|
||||
@@ -44,6 +44,14 @@ Dipendenze principali:
|
||||
|
||||
## Session sequence
|
||||
|
||||
The shared frontend is wrapped by `ShellProvider` (full preferences or a
|
||||
replaceable portal presentation adapter), then `AuthGate` (backend identity),
|
||||
then `AppShell`. Omics-specific DOM details belong only to `OmicsPortalAdapter`;
|
||||
credentials and principal validation belong to the server, never that adapter.
|
||||
Full/embedded do not duplicate the session workflow below. See
|
||||
[rendering architecture](application-shell.md) and
|
||||
[upstream identity](../install/authentication-upstream.md) for both boundaries.
|
||||
|
||||
The main path starts with a user question and ends with an SSE event. Reviewer decisions use the same channel and are persisted by the harness.
|
||||
|
||||
```mermaid
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
|
||||
ThothII is a **human-in-the-loop datamart builder**. It turns a natural-language question into validated SQL, and optionally a dbt datamart, through a **deterministic eight-phase NL-to-SQL workflow** in which the model *proposes* and a human reviewer *decides* at gates.
|
||||
|
||||
Production authentication uses local authentication or generic OIDC. `tht` is the only operator CLI.
|
||||
For sessions, roles, groups, diagnostics, and recovery, see the [authentication documentation](authentication.md).
|
||||
Production authentication uses local authentication, generic OIDC, or the
|
||||
trusted-proxy upstream path used by Omics. `tht` is the operator CLI for the
|
||||
installation and local/OIDC configuration. For roles and recovery, see
|
||||
[authentication](authentication.md). One React build supports full and embedded;
|
||||
[rendering architecture](application-shell.md) separates presentation from identity.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -78,20 +81,20 @@ The model proposes; a human reviewer decides at gates through widgets:
|
||||
|
||||
The frontend renders these widget descriptors (registry in `src/widgets/`). It rebuilds the live transcript in memory from the SSE stream (`src/store/sessionStore.ts`); it is **not persisted**.
|
||||
|
||||
## Curated and immutable Evidence
|
||||
## Evidence sources, local authority and search projections
|
||||
|
||||
The workspace repository is the publication boundary. The curator prepares `evidence/source/`,
|
||||
reviews units in `evidence/curated/`, validates them, and merges them. With `evidence.schema_version: 2`,
|
||||
the runtime materializes the full `evidence/` tree from the exact Git commit, but the renderer passes
|
||||
only `curated/**/*.md` from the immutable revision root to preprocessing. Sources, manifests, and
|
||||
evaluation data remain available for traceability. The runtime never modifies, stages, commits, or
|
||||
publishes the authoring repository.
|
||||
The workspace repository publishes revision-pinned workspace identities and Evidence sources.
|
||||
An initialized editable Evidence archive is maintained locally through external editors and
|
||||
explicit consolidation; normal preprocessing or source refresh must not overwrite its manual
|
||||
corrections. File save, active search generation and a later human Git commit/push are separate
|
||||
outcomes. See [the current Evidence contract](../contracts/curated-evidence-v4.md) and
|
||||
[source/publication boundaries](../contracts/workspace-evidence-v3.md).
|
||||
|
||||
Before indexing, the curated corpus from the pinned revision is validated. Each workspace has two
|
||||
physical Qdrant collections with different lifecycles. `reference` contains Schema, relationships,
|
||||
and Evidence and may be replaced or cleared by preprocessing; `memory` contains `memory` and
|
||||
`solved_question` records and is never preprocessing output. Only the `reference` collection has the
|
||||
sparse `bm25` vector with `idf`, and only the Evidence stage writes sparse values.
|
||||
Each workspace has separate Qdrant collections. `reference` contains Schema, relationships and
|
||||
Evidence and may be replaced or cleared by preprocessing. Memory uses its own dense/BM25
|
||||
projection, rebuilt from authoritative PostgreSQL cards rather than old vector payloads or
|
||||
session artifacts. Both collections can contain sparse vectors; their ownership and cleanup
|
||||
lifecycles remain separate. See [Memory](../gestione-memory.md).
|
||||
|
||||
The Administration control can clear the replaceable reference collection, LSH, corpus, and derived
|
||||
checkpoints. The operation preserves the memory collection and makes preprocessing required before
|
||||
@@ -101,7 +104,9 @@ the core can admit a new session.
|
||||
|
||||
- `tht -c`/`--config` is a **per-command** option. It must follow the subcommand, never precede it (`ThtRunner.buildArgv` enforces this).
|
||||
- `--json` output must be plain JSON on stdout. It is a machine-readable contract.
|
||||
- UI strings are in English. Document *content* stays in the workspace language because it is the actual data; only chrome and labels are in English.
|
||||
- UI strings support English and Italian, with English fallback. Session interaction language
|
||||
is pinned at creation; document content remains in the workspace language. See
|
||||
[shell and localization](../operations/shell-and-localization.md).
|
||||
- Each workspace defines identity and optional Evidence only. The PostgreSQL Metadata Catalog defines
|
||||
its DWH target and binding; secrets remain in the protected workspace secret store.
|
||||
- Settings are global (`backend/data/settings.json`: workspace/thinking); provider/model choices are
|
||||
@@ -110,6 +115,13 @@ the core can admit a new session.
|
||||
|
||||
## Runtime composition
|
||||
|
||||
PostgreSQL is the current database-metadata authority for all core consumers, not a deferred
|
||||
catalog-to-core integration. The historical research on a separate catalog service and
|
||||
`annotations.yaml` publication is superseded by ADRs 0004 and 0016. Preserve read-only DWH access,
|
||||
installation-local bindings/secrets, revision-pinned workspace identity, and fail-closed readiness
|
||||
when changing those boundaries. The exact snapshot interface is the
|
||||
[Catalog Schema Snapshot contract](../contracts/catalog-schema-snapshot.md).
|
||||
|
||||
The local stack is started by `./scripts/run-stack.sh` after the installation descriptor and
|
||||
`deploy/env/local.env` exist. `core` includes Pi. `catalog-db`, Qdrant, and the Ollama embedding
|
||||
service are internal Compose services; only the DWH and model-provider endpoint remain external.
|
||||
|
||||
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 186 KiB |
@@ -1,32 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Archify automated browser evidence · thothii-core-sequence.html</title>
|
||||
<style>
|
||||
*{box-sizing:border-box}body{margin:0;padding:24px;background:#e9eef5;color:#172033;font:14px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}header{max-width:1500px;margin:0 auto 18px}h1{margin:0 0 6px;font-size:20px}p{margin:0;color:#526176}.grid{max-width:1500px;margin:auto;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}figure{margin:0;padding:10px;background:white;border:1px solid #c9d4e3;border-radius:12px;box-shadow:0 10px 30px rgba(15,23,42,.08)}img{display:block;width:100%;height:auto;border:1px solid #e2e8f0}figcaption{padding:9px 4px 2px;color:#526176}@media(max-width:900px){.grid{grid-template-columns:1fr}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header><h1>Automated browser evidence</h1><p>thothii-core-sequence.html · visual-check containment pass · perceptual visual review pending</p></header>
|
||||
<main class="grid">
|
||||
<figure>
|
||||
<img src="thothii-core-sequence.visual-check.1440x900.light.png" alt="light 1440 by 900">
|
||||
<figcaption><strong>LIGHT</strong> · 1440×900 · containment pass</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="thothii-core-sequence.visual-check.1440x900.dark.png" alt="dark 1440 by 900">
|
||||
<figcaption><strong>DARK</strong> · 1440×900 · containment pass</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="thothii-core-sequence.visual-check.2048x1320.light.png" alt="light 2048 by 1320">
|
||||
<figcaption><strong>LIGHT</strong> · 2048×1320 · containment pass</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="thothii-core-sequence.visual-check.2048x1320.dark.png" alt="dark 2048 by 1320">
|
||||
<figcaption><strong>DARK</strong> · 2048×1320 · containment pass</figcaption>
|
||||
</figure>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,548 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"ok": true,
|
||||
"command": "visual-check",
|
||||
"evidenceKind": "automated-browser",
|
||||
"status": "pass",
|
||||
"visualReview": "pending",
|
||||
"artifact": {
|
||||
"path": "/Users/mp/projects/ThothII/docs/architecture/thothii-core-sequence.html",
|
||||
"sha256": "b521eb942f7889cfc3a5e29010546ba59eeab1cf485c22c533d271ccef9a28d5",
|
||||
"bytes": 716881
|
||||
},
|
||||
"state": {
|
||||
"detail": "read",
|
||||
"motion": "still"
|
||||
},
|
||||
"chrome": {
|
||||
"status": "available",
|
||||
"executable": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||
},
|
||||
"diagnostics": [],
|
||||
"containment": {
|
||||
"status": "pass",
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "light",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1194,
|
||||
"diagramWidth": 1164,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1600,
|
||||
"height": 1000,
|
||||
"theme": "light",
|
||||
"innerWidth": 1600,
|
||||
"innerHeight": 1000,
|
||||
"scrollWidth": 1600,
|
||||
"scrollHeight": 1000,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1242,
|
||||
"diagramWidth": 1212,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"theme": "light",
|
||||
"innerWidth": 1920,
|
||||
"innerHeight": 1080,
|
||||
"scrollWidth": 1920,
|
||||
"scrollHeight": 1080,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1402,
|
||||
"diagramWidth": 1372,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "light",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1818,
|
||||
"diagramWidth": 1768,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
}
|
||||
]
|
||||
},
|
||||
"readability": {
|
||||
"status": "pass",
|
||||
"minimumProjectedNodeTextPx": 6,
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "light",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1194,
|
||||
"diagramWidth": 1164,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1600,
|
||||
"height": 1000,
|
||||
"theme": "light",
|
||||
"innerWidth": 1600,
|
||||
"innerHeight": 1000,
|
||||
"scrollWidth": 1600,
|
||||
"scrollHeight": 1000,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1242,
|
||||
"diagramWidth": 1212,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"theme": "light",
|
||||
"innerWidth": 1920,
|
||||
"innerHeight": 1080,
|
||||
"scrollWidth": 1920,
|
||||
"scrollHeight": 1080,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1402,
|
||||
"diagramWidth": 1372,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "light",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1818,
|
||||
"diagramWidth": 1768,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
}
|
||||
]
|
||||
},
|
||||
"viewerChrome": {
|
||||
"status": "pass",
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "light",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1194,
|
||||
"diagramWidth": 1164,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1600,
|
||||
"height": 1000,
|
||||
"theme": "light",
|
||||
"innerWidth": 1600,
|
||||
"innerHeight": 1000,
|
||||
"scrollWidth": 1600,
|
||||
"scrollHeight": 1000,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1242,
|
||||
"diagramWidth": 1212,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"theme": "light",
|
||||
"innerWidth": 1920,
|
||||
"innerHeight": 1080,
|
||||
"scrollWidth": 1920,
|
||||
"scrollHeight": 1080,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1402,
|
||||
"diagramWidth": 1372,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "light",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1818,
|
||||
"diagramWidth": 1768,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
}
|
||||
]
|
||||
},
|
||||
"captures": {
|
||||
"status": "pass",
|
||||
"screenshots": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "light",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1194,
|
||||
"diagramWidth": 1164,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light",
|
||||
"file": "thothii-core-sequence.visual-check.1440x900.light.png"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "dark",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1194,
|
||||
"diagramWidth": 1164,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "dark",
|
||||
"file": "thothii-core-sequence.visual-check.1440x900.dark.png"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "light",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1818,
|
||||
"diagramWidth": 1768,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light",
|
||||
"file": "thothii-core-sequence.visual-check.2048x1320.light.png"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "dark",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1818,
|
||||
"diagramWidth": 1768,
|
||||
"viewBoxWidth": 1080,
|
||||
"minimumProjectedNodeTextPx": 7,
|
||||
"minimumProjectedNodeText": "browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "dark",
|
||||
"file": "thothii-core-sequence.visual-check.2048x1320.dark.png"
|
||||
}
|
||||
],
|
||||
"contactSheet": "thothii-core-sequence.visual-check.html"
|
||||
},
|
||||
"sidecars": {
|
||||
"receipt": "thothii-core-sequence.visual-check.json",
|
||||
"contactSheet": "thothii-core-sequence.visual-check.html"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 182 KiB |
@@ -1,32 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Archify automated browser evidence · thothii-runtime.html</title>
|
||||
<style>
|
||||
*{box-sizing:border-box}body{margin:0;padding:24px;background:#e9eef5;color:#172033;font:14px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}header{max-width:1500px;margin:0 auto 18px}h1{margin:0 0 6px;font-size:20px}p{margin:0;color:#526176}.grid{max-width:1500px;margin:auto;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}figure{margin:0;padding:10px;background:white;border:1px solid #c9d4e3;border-radius:12px;box-shadow:0 10px 30px rgba(15,23,42,.08)}img{display:block;width:100%;height:auto;border:1px solid #e2e8f0}figcaption{padding:9px 4px 2px;color:#526176}@media(max-width:900px){.grid{grid-template-columns:1fr}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header><h1>Automated browser evidence</h1><p>thothii-runtime.html · visual-check containment pass · perceptual visual review pending</p></header>
|
||||
<main class="grid">
|
||||
<figure>
|
||||
<img src="thothii-runtime.visual-check.1440x900.light.png" alt="light 1440 by 900">
|
||||
<figcaption><strong>LIGHT</strong> · 1440×900 · containment pass</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="thothii-runtime.visual-check.1440x900.dark.png" alt="dark 1440 by 900">
|
||||
<figcaption><strong>DARK</strong> · 1440×900 · containment pass</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="thothii-runtime.visual-check.2048x1320.light.png" alt="light 2048 by 1320">
|
||||
<figcaption><strong>LIGHT</strong> · 2048×1320 · containment pass</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="thothii-runtime.visual-check.2048x1320.dark.png" alt="dark 2048 by 1320">
|
||||
<figcaption><strong>DARK</strong> · 2048×1320 · containment pass</figcaption>
|
||||
</figure>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,548 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"ok": true,
|
||||
"command": "visual-check",
|
||||
"evidenceKind": "automated-browser",
|
||||
"status": "pass",
|
||||
"visualReview": "pending",
|
||||
"artifact": {
|
||||
"path": "/Users/mp/projects/ThothII/docs/architecture/thothii-runtime.html",
|
||||
"sha256": "ad19195852c7c643228663e5bf7f3cb273afb0456fedbe295d4df24bc345b6c7",
|
||||
"bytes": 724277
|
||||
},
|
||||
"state": {
|
||||
"detail": "read",
|
||||
"motion": "still"
|
||||
},
|
||||
"chrome": {
|
||||
"status": "available",
|
||||
"executable": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||
},
|
||||
"diagnostics": [],
|
||||
"containment": {
|
||||
"status": "pass",
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "light",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 968,
|
||||
"diagramWidth": 938,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 6.20735294117647,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1600,
|
||||
"height": 1000,
|
||||
"theme": "light",
|
||||
"innerWidth": 1600,
|
||||
"innerHeight": 1000,
|
||||
"scrollWidth": 1600,
|
||||
"scrollHeight": 1000,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1009,
|
||||
"diagramWidth": 979,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 6.478676470588235,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"theme": "light",
|
||||
"innerWidth": 1920,
|
||||
"innerHeight": 1080,
|
||||
"scrollWidth": 1920,
|
||||
"scrollHeight": 1080,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1172,
|
||||
"diagramWidth": 1142,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 7.557352941176471,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "light",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1583,
|
||||
"diagramWidth": 1533,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 9,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
}
|
||||
]
|
||||
},
|
||||
"readability": {
|
||||
"status": "pass",
|
||||
"minimumProjectedNodeTextPx": 6,
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "light",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 968,
|
||||
"diagramWidth": 938,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 6.20735294117647,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1600,
|
||||
"height": 1000,
|
||||
"theme": "light",
|
||||
"innerWidth": 1600,
|
||||
"innerHeight": 1000,
|
||||
"scrollWidth": 1600,
|
||||
"scrollHeight": 1000,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1009,
|
||||
"diagramWidth": 979,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 6.478676470588235,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"theme": "light",
|
||||
"innerWidth": 1920,
|
||||
"innerHeight": 1080,
|
||||
"scrollWidth": 1920,
|
||||
"scrollHeight": 1080,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1172,
|
||||
"diagramWidth": 1142,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 7.557352941176471,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "light",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1583,
|
||||
"diagramWidth": 1533,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 9,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
}
|
||||
]
|
||||
},
|
||||
"viewerChrome": {
|
||||
"status": "pass",
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "light",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 968,
|
||||
"diagramWidth": 938,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 6.20735294117647,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1600,
|
||||
"height": 1000,
|
||||
"theme": "light",
|
||||
"innerWidth": 1600,
|
||||
"innerHeight": 1000,
|
||||
"scrollWidth": 1600,
|
||||
"scrollHeight": 1000,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1009,
|
||||
"diagramWidth": 979,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 6.478676470588235,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"theme": "light",
|
||||
"innerWidth": 1920,
|
||||
"innerHeight": 1080,
|
||||
"scrollWidth": 1920,
|
||||
"scrollHeight": 1080,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1172,
|
||||
"diagramWidth": 1142,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 7.557352941176471,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "light",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1583,
|
||||
"diagramWidth": 1533,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 9,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light"
|
||||
}
|
||||
]
|
||||
},
|
||||
"captures": {
|
||||
"status": "pass",
|
||||
"screenshots": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "light",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 968,
|
||||
"diagramWidth": 938,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 6.20735294117647,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light",
|
||||
"file": "thothii-runtime.visual-check.1440x900.light.png"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900,
|
||||
"theme": "dark",
|
||||
"innerWidth": 1440,
|
||||
"innerHeight": 900,
|
||||
"scrollWidth": 1440,
|
||||
"scrollHeight": 900,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 968,
|
||||
"diagramWidth": 938,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 6.20735294117647,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 51,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "dark",
|
||||
"file": "thothii-runtime.visual-check.1440x900.dark.png"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "light",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1583,
|
||||
"diagramWidth": 1533,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 9,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "light",
|
||||
"file": "thothii-runtime.visual-check.2048x1320.light.png"
|
||||
},
|
||||
{
|
||||
"width": 2048,
|
||||
"height": 1320,
|
||||
"theme": "dark",
|
||||
"innerWidth": 2048,
|
||||
"innerHeight": 1320,
|
||||
"scrollWidth": 2048,
|
||||
"scrollHeight": 1320,
|
||||
"overflowX": false,
|
||||
"overflowY": false,
|
||||
"ok": true,
|
||||
"readerWidth": 1583,
|
||||
"diagramWidth": 1533,
|
||||
"viewBoxWidth": 1360,
|
||||
"minimumProjectedNodeTextPx": 9,
|
||||
"minimumProjectedNodeText": "Browser",
|
||||
"minimumProjectedNodeTextDetail": "context",
|
||||
"minimumRequiredNodeTextPx": 6,
|
||||
"readabilityOk": true,
|
||||
"hasLegend": true,
|
||||
"hasNavigationDock": true,
|
||||
"legendDockIntersectionArea": 0,
|
||||
"dockStageIntersectionArea": 0,
|
||||
"dockStageGap": 10.21875,
|
||||
"requiredDockStageGap": 10,
|
||||
"viewerChromeStageOk": true,
|
||||
"viewerChromeReserve": 41,
|
||||
"viewerChromeActive": true,
|
||||
"viewerChromeOk": true,
|
||||
"resolvedTheme": "dark",
|
||||
"file": "thothii-runtime.visual-check.2048x1320.dark.png"
|
||||
}
|
||||
],
|
||||
"contactSheet": "thothii-runtime.visual-check.html"
|
||||
},
|
||||
"sidecars": {
|
||||
"receipt": "thothii-runtime.visual-check.json",
|
||||
"contactSheet": "thothii-runtime.visual-check.html"
|
||||
}
|
||||
}
|
||||
@@ -244,5 +244,5 @@ The first installed consolidation performs this conversion automatically when th
|
||||
legacy manifest is present, then validates and activates the result. Preserve the
|
||||
existing checkout in backups before upgrading. The E1 validation used an isolated
|
||||
copy; E2 also converted and indexed all 35 units on the running local preview.
|
||||
See the [E1 validation report](../plans/2026-09-09-evidence-e1-validation.md) and
|
||||
[E2 validation report](../plans/2026-09-09-evidence-e2-validation.md).
|
||||
See the [E1 validation report](../reports/knowledge-archives-release.md) and
|
||||
[E2 validation report](../reports/knowledge-archives-release.md).
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
# Portal Shell Adapter v1
|
||||
|
||||
Contratto minimo della presentazione embedded. La revisione approvata il 2026-09-13
|
||||
sostituisce il precedente trasporto a eventi personalizzati con l'osservazione del
|
||||
documento condiviso. Non trasferisce identità, token o stato di autenticazione.
|
||||
|
||||
## Configurazione
|
||||
|
||||
Sul Mac:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: full
|
||||
defaultLocale: en
|
||||
```
|
||||
|
||||
Sul server Omics:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: embedded
|
||||
adapter: omics-portal
|
||||
```
|
||||
|
||||
Se `shell` o `mode` sono omessi, la modalità è embedded. L'adapter embedded
|
||||
predefinito è `omics-portal`; un nome sconosciuto è un errore di configurazione.
|
||||
Questi default sono normalizzati dal CLI prima della proiezione. Nel browser,
|
||||
shell interamente omessa ha gli stessi default, ma un oggetto `shell` parziale
|
||||
senza `mode` o `defaultLocale` viene rifiutato: non scrivere proiezioni a mano.
|
||||
Full non istanzia adapter. `defaultLocale` inizializza full; in embedded il locale
|
||||
proviene dal portale. L'autenticazione si configura separatamente dalla shell.
|
||||
|
||||
## API applicativa
|
||||
|
||||
```ts
|
||||
export type PortalSnapshot = {
|
||||
locale: string;
|
||||
theme: "light" | "dark";
|
||||
fullscreen: boolean;
|
||||
};
|
||||
|
||||
export interface PortalAdapter {
|
||||
subscribe(
|
||||
onState: (state: PortalSnapshot) => void,
|
||||
onError: (error: Error) => void,
|
||||
): () => void;
|
||||
}
|
||||
```
|
||||
|
||||
Una sottoscrizione installa gli osservatori e consegna lo snapshot iniziale senza
|
||||
richiedere messaggi all'altro applicativo. Gli aggiornamenti contengono snapshot
|
||||
completi e validati. La disiscrizione elimina tutti i listener e osservatori.
|
||||
La lingua viene risolta tramite i cataloghi UI, con fallback inglese.
|
||||
|
||||
## Implementazione Omics
|
||||
|
||||
L'integrazione monta React nel documento Django, non in un iframe.
|
||||
|
||||
| Dato | Fonte privata dell'adapter | Aggiornamento |
|
||||
| --- | --- | --- |
|
||||
| Locale | `data-lang` del selettore `.omics-language-select` | nuova pagina Django dopo `set_language` |
|
||||
| Tema | `data-bs-theme` su `html` | osservazione limitata a quell'attributo |
|
||||
| Fullscreen | stato effettivo del documento | evento del browser, inclusa uscita con Esc |
|
||||
|
||||
Il template Omics aggiornato allinea anche `html lang` alla lingua Django, ma
|
||||
la fonte dell'adapter rimane `select.omics-language-select[data-lang]`. Leggere
|
||||
il valore renderizzato evita di anticipare un cambio lingua prima che il form
|
||||
abbia successo. Cambiare soltanto `select.value` o `data-lang` senza il normale
|
||||
reload non è un trasporto runtime implementato per la lingua.
|
||||
|
||||
L'assenza del contesto host atteso produce un errore di integrazione; non abilita
|
||||
controlli locali. Non si introducono eventi `ready/state`, handshake, timeout,
|
||||
versioni dei messaggi o comandi duplicati. Selettori e dettagli Omics non devono
|
||||
essere letti dai componenti applicativi.
|
||||
|
||||
## Proprietà per modalità
|
||||
|
||||
| Funzione | Full | Embedded |
|
||||
| --- | --- | --- |
|
||||
| Header | ThothII | solo Omics |
|
||||
| Lingua | selettore locale | selettore Omics, normale reload Django |
|
||||
| Tema | toggle locale light/dark | stato Omics |
|
||||
| Fullscreen | controllo locale, stato reale | controllo Omics, stato reale |
|
||||
| Login/logout | ThothII local/OIDC; upstream non offre logout locale | autenticazione Omics esistente |
|
||||
| Nome utente | header ThothII | header Omics |
|
||||
| Rotellina amministrativa | mai | eventuale comando del portale |
|
||||
|
||||
## Accesso e continuità
|
||||
|
||||
Il server Omics verifica l'accesso a Datamart Builder e il proxy trasmette i
|
||||
principal header normalizzati al backend ThothII. La UI usa `/me`; non effettua
|
||||
un secondo login. Un altro portale deve soddisfare anche questo contratto server,
|
||||
oltre a fornire una nuova implementazione dell'adapter UI.
|
||||
|
||||
Il [contratto upstream](../install/authentication-upstream.md) specifica header,
|
||||
origine, rete e configurazioni incompatibili. Lo snapshot non può contenere
|
||||
`authenticated`, utente, ruoli, cookie o token; un evento browser non autorizza
|
||||
una richiesta API. Il prefisso API viene configurato separatamente prima del
|
||||
caricamento React, non viene dedotto dall'adapter.
|
||||
|
||||
Il logout del portale segue la sua navigazione. Una perdita di accesso rilevata
|
||||
dal server chiude lo stato protetto; un 403 di una singola operazione non equivale
|
||||
automaticamente a logout. La riconnessione degli eventi e il ritorno alla pagina
|
||||
ricontrollano l'accesso. Non si garantisce revoca istantanea di una connessione
|
||||
aperta in un'altra scheda attraverso il solo controllo iniziale del proxy.
|
||||
|
||||
Il cambio lingua può ricaricare la pagina: conservare la selezione della sessione,
|
||||
proteggere le modifiche non salvate e non avviare una nuova generazione al reload.
|
||||
Non si conserva una trascrizione integrale nel browser. La lingua della sessione
|
||||
rimane quella registrata nel manifest, secondo ADR 0022.
|
||||
|
||||
## Sostituzione e verifiche
|
||||
|
||||
Un nuovo adapter può usare un diverso documento o trasporto, ma deve rispettare
|
||||
la stessa sottoscrizione e mantenere la conoscenza del portale nella propria
|
||||
implementazione. Oggi `ShellProvider` istanzia direttamente `OmicsPortalAdapter`:
|
||||
per sostituirlo aggiornare quel punto e i nomi accettati in
|
||||
`tools/tht/internal/config/shell.go` e `frontend/src/api/runtime-config.ts`.
|
||||
Non è disponibile il caricamento dinamico di classi da una stringa YAML.
|
||||
Non occorre implementare ora iframe o un secondo portale.
|
||||
|
||||
La nuova implementazione deve pubblicare uno snapshot iniziale completo, poi gli
|
||||
aggiornamenti; segnalare contesto invalido; liberare tutti i listener alla
|
||||
disiscrizione. Locale ben formato ma non tradotto significa fallback inglese;
|
||||
locale assente/malformato e tema diverso da light/dark sono errori di integrazione.
|
||||
Non cambiare componenti applicativi o workflow per aggiungere selettori specifici
|
||||
del nuovo portale.
|
||||
|
||||
Verificare snapshot prima/dopo il montaggio, tema, fullscreen con Esc, cleanup,
|
||||
contesto host mancante, assenza di header ThothII embedded, accesso singolo,
|
||||
locale dopo reload e compatibilità del prefisso API. Full deve funzionare senza
|
||||
alcun elemento Omics presente.
|
||||
|
||||
Vedere anche [architettura del rendering](../architecture/application-shell.md)
|
||||
e [matrice di accettazione](../testing/authentication-manual-acceptance.md).
|
||||
@@ -4,7 +4,7 @@ This page describes the complete workspace Evidence lifecycle: where original ma
|
||||
|
||||
## Editable local Evidence
|
||||
|
||||
E1 adds [Curated Evidence v4 and a persistent local archive](contracts/curated-evidence-v4.md).
|
||||
E1 adds [Curated Evidence v4 and a persistent local archive](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/curated-evidence-v4.md).
|
||||
The visible title and payload fields are authoritative Markdown. New manual units need no
|
||||
external source; consolidation records their curator and distinguishes later corrections
|
||||
from original documentary provenance. The core archive API creates immutable candidates
|
||||
@@ -14,12 +14,12 @@ E2 adds **Administration → Evidence management**, actual host file paths, comp
|
||||
browsing and filtering, and the installed `tht workspace evidence consolidate
|
||||
--workspace <id>` command. Edit files externally, consolidate to activate them, then
|
||||
review and run Git manually. Runtime consumes only the active local snapshot.
|
||||
The [v4 contract](contracts/curated-evidence-v4.md#administration-and-installed-command)
|
||||
The [v4 contract](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/curated-evidence-v4.md#administration-and-installed-command)
|
||||
describes host mounting, first conversion, failure recovery and Clear behavior.
|
||||
The local PSD preview has 35 converted and indexed units. E3 adds explicit import/refresh
|
||||
from local drafts and configured HTTP/S3 sources, durable current/proposed comparisons,
|
||||
and keep/replace decisions with activation and retry. See
|
||||
[Import drafts and refresh sources](contracts/curated-evidence-v4.md#import-drafts-and-refresh-sources).
|
||||
[Import drafts and refresh sources](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/curated-evidence-v4.md#import-drafts-and-refresh-sources).
|
||||
Workflow gate corrections remain the subsequent shared increment, X1.
|
||||
|
||||
## Existing repository publication path
|
||||
@@ -92,7 +92,7 @@ Join orders using the order number, financial year and company.
|
||||
|
||||
Use `tht evidence migrate <workspace-root>` for deterministic legacy conversion. The
|
||||
conversion preserves typed content and initializes an archive baseline; it does not
|
||||
activate the local corpus. See the [v4 contract](contracts/curated-evidence-v4.md) for
|
||||
activate the local corpus. See the [v4 contract](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/curated-evidence-v4.md) for
|
||||
all eight kinds, provenance, file layout and the E1/E2 boundary.
|
||||
|
||||
## Legacy v3 representation
|
||||
@@ -262,5 +262,5 @@ Formulas use a format distinct from document Evidence. A formula proposed during
|
||||
|
||||
## Contract references
|
||||
|
||||
- [Workspace Evidence v3 contract](contracts/workspace-evidence-v3.md)
|
||||
- [Preprocessing CLI contract](contracts/workspace-preprocessing-cli.md)
|
||||
- [Workspace Evidence v3 contract](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/workspace-evidence-v3.md)
|
||||
- [Preprocessing CLI contract](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/workspace-preprocessing-cli.md)
|
||||
|
||||
@@ -128,6 +128,51 @@ endpoint expects a model name different from the catalog key.
|
||||
Provider integrations remain declarative. Do not register providers from
|
||||
`harness/.pi/extensions/`; those extensions implement the workflow and human gates only.
|
||||
|
||||
### Qwen 3.6 sessions and thinking controls
|
||||
|
||||
For Qwen served through a vLLM-compatible chat template, declare the following inside the
|
||||
model's `session` block, alongside its context and output limits:
|
||||
|
||||
```yaml
|
||||
reasoning: true
|
||||
compatibility:
|
||||
supportsDeveloperRole: false
|
||||
supportsReasoningEffort: false
|
||||
supportsStore: false
|
||||
maxTokensField: max_tokens
|
||||
thinkingFormat: qwen-chat-template
|
||||
```
|
||||
|
||||
This makes Pi send `chat_template_kwargs.enable_thinking` from the selected thinking level,
|
||||
with `preserve_thinking: true`. Choose **off** to explicitly disable thinking. The alternative
|
||||
`thinkingFormat: qwen` is for endpoints expecting top-level `enable_thinking`. Both formats
|
||||
require `reasoning: true`; declaring `reasoning: false` does not tell the server to disable
|
||||
thinking. Omit `thinkingFormat` to preserve Pi's default behavior for other providers.
|
||||
|
||||
Regenerate projections with the updated host CLI and recreate the local core container after
|
||||
rebuilding it. Do not add these fields directly to generated Pi files. These controls do not
|
||||
force tool calls or certify the workflow; perform the operator verification above.
|
||||
|
||||
```sh
|
||||
tht --installation /absolute/path/thothii-installation.yaml installation generate
|
||||
```
|
||||
|
||||
Use the model identifier exposed by your endpoint, such as `qwen3.6-35b-a3b`, and limits
|
||||
supported by that deployment. The thinking format configures the Pi session adapter;
|
||||
metadata generation continues to use its separate LiteLLM settings.
|
||||
|
||||
If a session displays text such as `{"type":"bash","command":"tht session show … --json"}`
|
||||
and never opens a review widget, that text is not an executed tool call. A verified cause
|
||||
was the Evidence JSON extension being loaded into interactive sessions and forcing
|
||||
`response_format: {type: "json_object"}`. Upgrade to the core image containing the fix:
|
||||
the extension belongs in `.pi/evidence-extensions/` and is loaded explicitly only by
|
||||
Evidence authoring. It must not also remain in the automatically loaded `.pi/extensions/`
|
||||
directory. Regenerating model configuration alone does not remove an extension from an old image.
|
||||
|
||||
After upgrading, reload the browser and resume the session. Verify that Pi executes
|
||||
`tht session show` and opens a review widget. This fix does not require changing the Qwen
|
||||
server, forcing every turn to call a tool, or teaching the model to print tool-call JSON.
|
||||
|
||||
## Authentication
|
||||
|
||||
Every provider chooses one explicit mode:
|
||||
|
||||
@@ -226,5 +226,5 @@ error. Preparation is repeatable and checks migration checksums.
|
||||
See [the M1 specification](plans/2026-09-08-memory-m1-spec.md) and
|
||||
[ADR 0018](adr/0018-use-postgres-for-memory-and-qdrant-for-retrieval.md) for the
|
||||
approved scope and acceptance boundaries.
|
||||
See [M2 implementation and validation](plans/2026-09-09-memory-m2-validation.md)
|
||||
See [M2 implementation and validation](reports/knowledge-archives-release.md)
|
||||
for the retrieval checks and real embedding test command.
|
||||
|
||||
@@ -4,10 +4,30 @@ This guide is for a reviewer using a configured ThothII installation. Installati
|
||||
publication, preprocessing, and database administration are separate paths; links to them are at
|
||||
the end of this page.
|
||||
|
||||
## Standalone or inside Omics
|
||||
|
||||
In **full** mode, ThothII has its own red header. Sign in using the installation's
|
||||
local account or the configured identity provider. The header lets you select
|
||||
English/Italian, light/dark, and fullscreen; Esc exits fullscreen. Open the user
|
||||
name menu to log out of ThothII. OIDC logout does not necessarily log out other
|
||||
applications using the same provider.
|
||||
|
||||
In **embedded** mode, first sign in to Omics and choose **Datamart Builder** in
|
||||
its left menu. ThothII opens with that authenticated identity: there is no second
|
||||
login or duplicate header. Use Omics's language, theme, fullscreen and logout
|
||||
controls. If portal access expires, return to Omics, sign in and reopen the page.
|
||||
|
||||
The Mac starts in English unless the browser remembers another choice. Changing
|
||||
the UI language affects labels, not saved domain content. A new session takes
|
||||
the selected language for the model's questions and reviewer choices; an existing
|
||||
session retains its saved language when resumed. Omics's language change reloads
|
||||
the page: confirm or cancel any unsaved-work warning. Reopening the saved session
|
||||
selection shows documents; it does not automatically restart generation.
|
||||
|
||||
## Before creating a session
|
||||
|
||||
An administrator must have selected a workspace and configured the installation-wide provider,
|
||||
model, and thinking settings. The New session form deliberately asks only for the question.
|
||||
model, and thinking settings. The new-question form deliberately asks only for the question.
|
||||
|
||||
The workspace is a pinned Git revision. A subsequent workspace update cannot alter a session
|
||||
already created from an earlier revision. If a workspace cannot reach its configured runtime DWH,
|
||||
@@ -15,7 +35,9 @@ new sessions are refused before any session state is written.
|
||||
|
||||
## Create and review a session
|
||||
|
||||
1. Sign in and select **New session**.
|
||||
1. Sign in and select **Session** (**Sessione** in Italian). If a session is already
|
||||
open and unfinished, this returns to it without restarting it. Otherwise it
|
||||
opens a new question; no session is created until you submit that question.
|
||||
2. Enter a precise business question, including the relevant time period and desired output. For
|
||||
example: “List patients discharged in the last 30 days, with ward and discharge date.”
|
||||
3. Review each gate and make the decision requested by the widget. A choice with a decision payload
|
||||
@@ -37,6 +59,19 @@ The workflow phases are fixed:
|
||||
|
||||
## Resume, archive, and the meaning of saved state
|
||||
|
||||
In Administration, the dot beside **Workspace** is green when readiness is
|
||||
confirmed and red otherwise. Hover the button for the exact state; assistive
|
||||
technology receives the same description. Select Workspace to inspect preparation.
|
||||
|
||||
The session sidebar has two accordion sections: **Active sessions** and
|
||||
**Archive**, both initially closed. Only their headers appear below the scope tabs.
|
||||
Inside each nonempty list, **Select all** selects only that list; its delete action
|
||||
also applies only to the selected sessions in that list. The other list's selection
|
||||
is preserved. Opening a section closes the other; clicking the open section closes
|
||||
it too. Empty lists show only "No sessions yet." Long lists scroll inside
|
||||
their own panels. Here active means not archived, not necessarily a running model
|
||||
process. Existing groups and session actions remain inside those sections.
|
||||
|
||||
The sidebar lists sessions and their current lifecycle. Resuming returns to the last incomplete
|
||||
phase. A finalized or archived session cannot be resumed.
|
||||
|
||||
@@ -54,4 +89,5 @@ happen from the workflow’s point of view.
|
||||
- To author material the workflow can retrieve, use [Evidence](evidence.md). A proposal from a
|
||||
session does not become Evidence automatically: a curator must review and publish it in Git.
|
||||
- For login and access recovery, use [local authentication](install/authentication-local.md) or
|
||||
[OIDC authentication](install/authentication-oidc.md).
|
||||
[OIDC authentication](install/authentication-oidc.md) for full, or contact the
|
||||
portal administrator for [embedded/upstream access](install/shell-and-language.md).
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
# ThothII documentation
|
||||
|
||||
ThothII is a human-reviewed datamart builder. It turns a question into validated SQL through an
|
||||
eight-phase workflow: the model proposes; a reviewer makes the decisions that are persisted.
|
||||
ThothII turns a natural-language question into reviewed SQL. The model proposes;
|
||||
a human reviewer decides which interpretations, sources and results to accept.
|
||||
|
||||
Start with the path that matches the work you need to do:
|
||||
This is the public product manual. Start with the task you need to perform:
|
||||
|
||||
| I need to… | Start here |
|
||||
| --- | --- |
|
||||
| Install or operate one instance | [Install and first start](install/first-start.md) |
|
||||
| Add, update, or prepare a workspace | [Workspace operations](operations/workspaces.md) |
|
||||
| Ask a question and review the SQL workflow | [User guide](guida-utente.md) |
|
||||
| Configure and refresh an authoritative database catalog | [Database management](operations/database-management.md) |
|
||||
| Author and publish domain Evidence | [Evidence](evidence.md) |
|
||||
| Understand boundaries and persistence | [Architecture overview](architecture/overview.md) |
|
||||
| Understand the product and its boundaries | [What ThothII does](product-overview.md) |
|
||||
| Install on Mac, Windows through WSL2, or Linux | [Italian procedure](install/standalone-manual-it.md) · [English procedure](install/standalone-manual-en.md) |
|
||||
| Choose display mode and language | [Display mode and language](install/shell-and-language.md) |
|
||||
| Configure login | [Local accounts](install/authentication-local.md) · [OIDC](install/authentication-oidc.md) |
|
||||
| Configure model providers | [Model configuration](general/pi-configuration.md) |
|
||||
| Prepare a domain workspace | [Workspaces](operations/workspaces.md) |
|
||||
| Configure databases and reviewed descriptions | [Database management](operations/database-management.md) |
|
||||
| Ask a question and review SQL | [User guide](guida-utente.md) · [Workflow](skills.md) |
|
||||
| Maintain domain knowledge | [Evidence](evidence.md) · [Memory](usage/memory.md) |
|
||||
|
||||
## How the documentation is organised
|
||||
## Scope of this manual
|
||||
|
||||
- **Install and operate** documents host-side setup, authentication, lifecycle, workspaces, and
|
||||
Pi administration.
|
||||
- **Use ThothII** documents the two application paths: reviewed NL→SQL sessions and administrative
|
||||
database management.
|
||||
- **Architecture and contracts** explain why the system behaves as it does and define the
|
||||
machine-facing boundaries. Consult them when integrating or changing an implementation; they
|
||||
are not a substitute for an operator runbook.
|
||||
The manual covers the product, installation, use and administration. Architecture,
|
||||
code contracts, design decisions, implementation plans, test reports and site-specific
|
||||
deployment handoffs are developer/project material maintained in the repository;
|
||||
they are not pages of this site and are not included in its search index.
|
||||
|
||||
The host-side `tht` command is the operator interface. The Python `tht` inside `harness/` is a
|
||||
different, internal workflow CLI invoked by the core. In examples, use an absolute installation
|
||||
descriptor path whenever discovery is not unambiguous.
|
||||
The installation procedures distinguish checked documentation from platform and
|
||||
functional tests that still require execution. A clone does not transfer another
|
||||
installation's credentials, data or network access.
|
||||
|
||||
The host-side `tht` command operates an installation. The Python workflow CLI inside
|
||||
the runtime is a separate internal interface; do not substitute its commands for
|
||||
the host installation procedure.
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
# Local authentication
|
||||
|
||||
Use local mode for a standalone PC or Mac. Configure it through `tht`; passwords are entered at an
|
||||
Use local mode for a standalone PC or Mac, with `shell.mode: full` and
|
||||
`shell.defaultLocale: en` in the installation descriptor. Presentation and
|
||||
authentication are independent: selecting full does not create accounts. Omics
|
||||
embedded instead uses the [upstream guide](shell-and-language.md), not local users.
|
||||
|
||||
Configure local authentication through `tht`; passwords are entered at an
|
||||
echo-free prompt or read from a protected `--password-file`, never from a command argument.
|
||||
|
||||
## Bootstrap
|
||||
@@ -56,6 +61,11 @@ machine use; JSON output is pristine on stdout.
|
||||
|
||||
## Session behavior and recovery
|
||||
|
||||
Full shows its own login form and, after login, the verified display name in its
|
||||
header. The name menu contains Log out. This sends a CSRF-protected request to
|
||||
`/api/auth/logout`, revokes the session and returns to login. Language/theme
|
||||
preferences may remain in the browser; they are not credentials.
|
||||
|
||||
An ordinary login expires after 2 hours idle or 12 hours absolute. Selecting **Remember me** makes
|
||||
the cookie persistent and changes the limits to 7 days idle or 30 days absolute. Remembered
|
||||
sessions survive a browser and backend restart, but not a user revision change, configuration
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
# Generic OIDC authentication
|
||||
|
||||
Use this guide for **ThothII's own login**, normally `shell.mode: full` on an
|
||||
autonomous server. It is not the integration procedure for an already logged-in
|
||||
Omics user. That deployment uses [embedded/upstream](shell-and-language.md),
|
||||
even when Omics's identity provider is Authentik.
|
||||
|
||||
OIDC mode supports a standards-based provider. The browser flow is generic: Authorization Code,
|
||||
PKCE S256, state, nonce, issuer/signature/audience/expiry validation, and the fixed callback
|
||||
`<publicUrl>/api/auth/oidc/callback`. The browser and API must use the same origin; configure the
|
||||
reverse proxy to preserve that public origin and callback path.
|
||||
|
||||
`publicUrl` is the public origin, without an application subpath. The current
|
||||
full OIDC browser entry and callback use `/api/auth/oidc/login` and
|
||||
`/api/auth/oidc/callback`; arbitrary prefixed OIDC hosting is not implemented by
|
||||
selecting a different `backendBaseUrl`.
|
||||
|
||||
Configure the installation with `tht`:
|
||||
|
||||
```sh
|
||||
@@ -18,6 +28,9 @@ The OIDC client secret is supplied through the protected secret bundle under the
|
||||
`THT_OIDC_CLIENT_SECRET`; it is never written into `auth.yaml`. The default scopes are exactly
|
||||
`openid`, `profile`, and `email`.
|
||||
|
||||
Keep `AUTH_MODE` unset when using this file. A simultaneously mounted local/OIDC
|
||||
configuration and `AUTH_MODE=upstream` is an error, not a fallback chain.
|
||||
|
||||
The non-secret OIDC configuration has this exact shape (replace angle-bracket placeholders with
|
||||
operator values):
|
||||
|
||||
@@ -91,4 +104,14 @@ Any authentication failure prevents activation according to the static or live s
|
||||
relevant diagnostic surface.
|
||||
|
||||
The complete closed diagnostic-code union and exact role-to-permission expansion are in the
|
||||
[authentication architecture](../architecture/authentication.md).
|
||||
[authentication architecture](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/architecture/authentication.md).
|
||||
|
||||
## Browser login and logout
|
||||
|
||||
ThothII redirects the browser to the provider and creates its own opaque session
|
||||
after validating the callback. An existing provider SSO session may avoid another
|
||||
password prompt, but this remains a distinct ThothII login/session, unlike Omics
|
||||
upstream. Full's name menu logs out of ThothII only. It does not revoke the
|
||||
provider session or log out other applications, so a subsequent login can return
|
||||
immediately through SSO. No provider token is placed in the UI adapter or browser
|
||||
storage. See the [manual acceptance matrix](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/testing/authentication-manual-acceptance.md).
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
# Autenticazione tramite portale e proxy fidato
|
||||
|
||||
Questa è la modalità **upstream** usata dall'integrazione Omics. Non è il login
|
||||
OIDC diretto di ThothII: l'utente accede a Omics come già fa, poi sceglie
|
||||
Datamart Builder e trova ThothII già autenticato. Non deve essere creato un utente
|
||||
locale ThothII né effettuato un secondo scambio OIDC dall'applicazione embedded.
|
||||
|
||||
## Il confine di fiducia
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor U as Utente già autenticato
|
||||
participant N as Nginx Omics
|
||||
participant D as Django Omics
|
||||
participant T as Core ThothII upstream
|
||||
U->>D: Apri Datamart Builder
|
||||
D-->>U: Pagina autorizzata con mount React
|
||||
U->>N: GET /datamart-builder/api/me (cookie Omics)
|
||||
N->>D: Subrequest interna /datamart-builder/api-auth
|
||||
D-->>N: 200 + identità verificata, oppure 403
|
||||
N->>T: GET /me + intestazioni normalizzate (solo se autorizzato)
|
||||
T-->>U: Identità e permessi applicativi, oppure rifiuto
|
||||
```
|
||||
|
||||
L'header e l'adapter JavaScript non autenticano nessuno. Il backend accetta una
|
||||
richiesta upstream solo con un'identità valida ricevuta da un percorso di rete
|
||||
fidato. Gli header non sono firmati da ThothII: la protezione è il proxy che
|
||||
verifica la sessione e sovrascrive l'identità, insieme all'isolamento del core.
|
||||
Un core upstream direttamente raggiungibile da client non fidati è una falla,
|
||||
non una modalità alternativa di accesso.
|
||||
|
||||
## Configurazione del core
|
||||
|
||||
Per Omics il descrittore pubblico deve contenere:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: embedded
|
||||
defaultLocale: en
|
||||
adapter: omics-portal
|
||||
```
|
||||
|
||||
Separatamente, il **processo core** deve ricevere `AUTH_MODE=upstream`. Definirlo
|
||||
nell'override Compose approvato e incluso nell'installazione; una variabile nel
|
||||
file di interpolazione `.env` non viene passata automaticamente al container:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
core:
|
||||
environment:
|
||||
AUTH_MODE: upstream
|
||||
```
|
||||
|
||||
È solo il frammento di selezione auth, non un file Compose completo né una
|
||||
configurazione di rete sufficiente. Non aggiunge porte pubbliche.
|
||||
|
||||
Condizioni obbligatorie:
|
||||
|
||||
1. Nessun `auth.yaml` local/OIDC deve essere effettivamente montato al percorso
|
||||
letto dal core (default `/run/thothii-auth/auth.yaml`). Se è presente insieme
|
||||
ad `AUTH_MODE`, l'avvio fallisce. Non impostare `AUTH_MODE=local` o `oidc`:
|
||||
questi due modi si selezionano dal file, non da quella variabile.
|
||||
2. Non configurare `authentication.runtimeProjection` per questo percorso: è la
|
||||
proiezione delle configurazioni cookie local/OIDC, non l'identità Omics.
|
||||
Nemmeno `THT_AUTH_RUNTIME_PROJECTION_ROOT` deve attivarla nel core.
|
||||
3. Il descrittore e Compose base continuano a richiedere `authentication.configDirectory`
|
||||
e `THT_AUTH_CONFIG_ROOT` coerenti. Per una nuova installazione upstream usare
|
||||
una directory dedicata senza `auth.yaml`, non cancellare la configurazione di
|
||||
un'installazione esistente. I cambi di modalità richiedono un piano separato.
|
||||
4. Non esiste `tht auth configure --mode upstream`: il CLI configura gli utenti
|
||||
locali o l'OIDC diretto. Conservare il percorso proxy già operativo per Omics.
|
||||
5. `profile: server`, storage delle sessioni e `THOTH_PUBLIC_EXPOSURE` hanno propri
|
||||
vincoli, che rimangono attivi. La shell embedded non li soddisfa automaticamente.
|
||||
|
||||
Il sorgente considera upstream un percorso di compatibilità con il proxy; è
|
||||
quello usato dall'integrazione Omics corrente. `none` e `mock` sono per sviluppo/test,
|
||||
non soluzioni a errori di configurazione in produzione.
|
||||
|
||||
## Intestazioni richieste all'ingresso del core
|
||||
|
||||
| Header | Regola ThothII | Valore Omics |
|
||||
| --- | --- | --- |
|
||||
| `X-Thoth-Principal-Issuer` | Stringa stabile, obbligatoria | `portal` |
|
||||
| `X-Thoth-Principal-Subject` | ID stabile dell'utente, obbligatorio | `str(user.pk)` Django |
|
||||
| `X-Thoth-Principal-Display-Name` | Facoltativo, se presente non vuoto | Nome completo o username |
|
||||
| `X-Thoth-Is-Admin` | Obbligatorio: `0`, `1`, `false` o `true` | Risultato di `is_authentik_admin(user)` |
|
||||
|
||||
Le stringhe sono ripulite degli spazi esterni, devono avere al massimo 512
|
||||
caratteri e non contenere caratteri di controllo. Header mancanti o invalidi
|
||||
producono 401. `false`/`0` assegna il ruolo `user`; `true`/`1` assegna `user` e
|
||||
`admin`. Il core espande i permessi dal proprio catalogo, non da un array inviato
|
||||
dal browser. `/me` richiede `session.use`.
|
||||
|
||||
La coppia `(issuer, subject)` identifica il proprietario delle sessioni.
|
||||
Non sostituire il subject con un nome visualizzato o un'email modificabile; non
|
||||
cambiare issuer/subject di utenti esistenti per correggere un problema grafico.
|
||||
Passare da identità `portal` a identità OIDC diretta non migra la proprietà dei dati.
|
||||
|
||||
## Omics: percorsi e componenti esatti
|
||||
|
||||
| Percorso | Destinazione e funzione |
|
||||
| --- | --- |
|
||||
| `/kokoro/datamart-builder/` | Pagina Django con `datamart_builder.access` |
|
||||
| `/datamart-builder/config.js` | Config pubblico del frontend, senza cache |
|
||||
| `/datamart-builder/assets/…` | Asset frontend risolti dal manifest Vite |
|
||||
| `/datamart-builder/api/…` | Nginx con `auth_request`, poi core senza il prefisso |
|
||||
| `/_thothii_auth` | Location Nginx interna, non un login pubblico |
|
||||
| `/datamart-builder/api-auth` | Django verifica sessione Omics e capability |
|
||||
|
||||
Nel repository Omics:
|
||||
|
||||
- `kokoro/datamart_catalog_views.py`: `DatamartBuilderView` e
|
||||
`datamart_builder_api_auth`; la verifica API risponde 200 o 403, anche 403
|
||||
quando la sessione è assente/scaduta. Non trasforma l'API in una pagina di login.
|
||||
- `nginx/nginx.conf`: API direttamente a `thothii-core:8787`, config e asset a
|
||||
`thothii-frontend:8080`; verificare alias e reti Docker effettivi sul server.
|
||||
- `templates/kokoro/datamart_builder.html`: mount, config e override del prefisso.
|
||||
- `kokoro/templatetags/vite.py`: manifest da
|
||||
`http://thothii-frontend:8080/.vite/manifest.json`, cache Django di 30 secondi.
|
||||
|
||||
Nginx usa il cookie Omics nella subrequest a Django. Sulle richieste al core
|
||||
sovrascrive i quattro header con i risultati della verifica e rimuove
|
||||
`Cookie`, `Authorization` e `X-Authenticated-User`. Nessuna password o token del
|
||||
portale deve essere copiato nel config pubblico, nello snapshot adapter o in Web Storage.
|
||||
`GET /datamart-builder/api/me` restituisce l'identità e i permessi; in upstream
|
||||
`session` e `csrfToken` sono `null`: non viene creata una sessione-cookie ThothII.
|
||||
|
||||
## Non confondere i due percorsi proxy
|
||||
|
||||
L'esempio generico `deploy/nginx-authenticated-proxy.conf.example` usa **due hop**:
|
||||
proxy host → frontend Nginx ThothII → core. Sul tratto privato verso il frontend
|
||||
trasporta `X-Thoth-Trusted-Principal-*` e `X-Thoth-Trusted-Is-Admin`; il frontend
|
||||
li converte nei quattro header del core e li elimina prima dell'inoltro.
|
||||
|
||||
Omics usa invece **Nginx Omics → core direttamente** per le API e invia gli header
|
||||
normalizzati senza `Trusted`. Non incollare l'esempio a due hop in questa location:
|
||||
la famiglia di header sbagliata produce 401. In entrambi i casi i valori devono
|
||||
venire dalla verifica server, mai dagli header del client. Il tratto privato del
|
||||
percorso generico deve essere inaccessibile ai client non fidati.
|
||||
|
||||
## Origine delle richieste e stream
|
||||
|
||||
Browser e API devono restare sullo stesso origin. Il frontend accetta `/api` o un
|
||||
prefisso same-origin come `/datamart-builder/api`, non un URL `http://core:8787`.
|
||||
In upstream le scritture con `Origin` sono confrontate con protocollo e Host
|
||||
percepiti dal core; non usano il token CSRF della sessione ThothII local/OIDC.
|
||||
Le richieste senza Origin hanno il trattamento non-browser: l'autenticazione del
|
||||
proxy rimane indispensabile anche per esse.
|
||||
|
||||
Nel Nginx Omics esaminato il TLS termina a monte e una mappa **esatta** converte
|
||||
`https://aritmolab.policlinicosandonato.it` in
|
||||
`http://aritmolab.policlinicosandonato.it` per il confronto interno. Le altre origini
|
||||
rimangono invariate e devono essere negate quando non coincidono. È una scelta
|
||||
specifica della topologia corrente, non un modello da estendere con wildcard,
|
||||
cancellazione di Origin o riscrittura incondizionata. Verificare Host/protocollo
|
||||
al core e i dinieghi cross-origin nella topologia realmente rilasciata.
|
||||
|
||||
La location API disabilita buffering/cache per SSE e mantiene timeout lunghi.
|
||||
`auth_request` verifica ogni nuova richiesta, ma non interrompe istantaneamente
|
||||
uno stream già aperto quando il portale revoca l'utente. ThothII ricontrolla `/me`
|
||||
al ritorno alla pagina e alla riconnessione degli eventi; non promettere revoca
|
||||
istantanea fra tutte le schede.
|
||||
|
||||
## Logout, rientro e diagnosi
|
||||
|
||||
In embedded logout e successivo login sono di Omics. ThothII non chiama
|
||||
`/auth/logout`, non cancella il cookie Django e non apre un suo login.
|
||||
Il rifiuto 401/403 di `/me` rimuove lo stato protetto e richiede il rientro dal
|
||||
portale. Un 403 su una singola operazione non equivale al logout dell'applicazione.
|
||||
|
||||
| Sintomo | Controllo mirato |
|
||||
| --- | --- |
|
||||
| Secondo header | Config servito: deve essere embedded, non full |
|
||||
| Nessuna UI e errore preferenze | Selettore Omics `data-lang` e `html data-bs-theme` |
|
||||
| `/me` 401 dal core | Header obbligatori, famiglia Trusted/normalizzata, percorso proxy |
|
||||
| `/me` 403 dal proxy | Sessione Omics e capability `datamart_builder.access` |
|
||||
| `/me` funziona ma POST 403 | Distinguere permesso operativo da mismatch Origin/Host/protocollo |
|
||||
| 502 o asset assenti | Alias/rete Docker e manifest Vite; attesa cache manifest 30 s |
|
||||
| Avvio core rifiutato | Coesistenza di `auth.yaml` o runtime projection con `AUTH_MODE` |
|
||||
| Logout full seguito da rientro IdP immediato | Il logout ThothII non è logout globale OIDC |
|
||||
|
||||
Non raccogliere cookie, token, segreti o dump completi delle configurazioni nei
|
||||
report. Registrare codici HTTP, nomi dei percorsi, revisioni e risultati dei test.
|
||||
|
||||
Consegna e rilascio: [procedura Omics](../operations/shell-and-localization.md#verifica-prima-del-deploy-server).
|
||||
Collaudo obbligatorio: [matrice di accettazione](../testing/authentication-manual-acceptance.md).
|
||||
@@ -1,7 +1,14 @@
|
||||
# Authentik provider configuration
|
||||
|
||||
ThothII uses generic OIDC in the browser. Authentik provides the identity provider and group
|
||||
catalog without adding a proprietary login flow.
|
||||
For **full with direct OIDC**, ThothII uses generic OIDC in the browser. Authentik
|
||||
provides the identity provider and group catalog without adding a proprietary flow.
|
||||
The provider/client/group setup below applies to that case only.
|
||||
|
||||
For **embedded in Omics**, retain Omics's existing Authentik authentication and
|
||||
configure ThothII as upstream. Omics verifies `datamart_builder.access` and
|
||||
administrator status and the proxy supplies the identity; no additional ThothII
|
||||
OIDC client, login or local user is required for that path. Follow the
|
||||
[portal integration guide](shell-and-language.md).
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
# Replace every absolute placeholder. Select exactly one Git transport override.
|
||||
schemaVersion: 2
|
||||
profile: local
|
||||
shell:
|
||||
mode: full
|
||||
defaultLocale: en
|
||||
projectDirectory: "/absolute/path/to/ThothII"
|
||||
envFile: "/absolute/path/to/ThothII/deploy/env/local.env"
|
||||
workspaceRepository:
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
# Replace every absolute placeholder. Select exactly one Git transport override.
|
||||
schemaVersion: 2
|
||||
profile: server
|
||||
# Standalone server with protected direct OIDC auth, not the Omics upstream path.
|
||||
# For Omics use authentication-upstream.md: embedded, no auth runtime projection.
|
||||
shell:
|
||||
mode: full
|
||||
defaultLocale: en
|
||||
projectDirectory: "/absolute/path/to/ThothII"
|
||||
envFile: "/absolute/path/to/thothii-server-operator/server.env"
|
||||
workspaceRepository:
|
||||
|
||||
@@ -1,82 +1,63 @@
|
||||
# Install and first start
|
||||
|
||||
This is the supported local installation path. It creates an installation-local configuration and
|
||||
starts the Compose stack; it does not create a workspace repository or a database catalog entry.
|
||||
Use the guided procedure for a fresh installation:
|
||||
|
||||
## Prerequisites and boundaries
|
||||
- [Italian guided installation](standalone-manual-it.md)
|
||||
- [English guided installation](standalone-manual-en.md)
|
||||
|
||||
Install Docker Engine with Compose v2, plus the host `tht` command. On macOS or Linux, install the
|
||||
host command from the repository with `./scripts/install-tht.sh`; Windows uses
|
||||
`./scripts/install-tht.ps1`. The installer builds or verifies the native command and checks that
|
||||
`tht` is resolvable on `PATH`.
|
||||
The procedure covers Windows through Ubuntu WSL2, macOS, and Linux including an Omarchy/Arch-like
|
||||
host. It uses the application clone, one installation secret bundle, protected repository
|
||||
credentials when needed, and a terminal command. No host Node.js, Python or Pi installation is
|
||||
required.
|
||||
|
||||
The stack contains `frontend`, `core`, `catalog-db`, `qdrant`, `embedding`, and the one-shot
|
||||
`embedding-model-init` and `catalog-migrate` services. DWH and model-provider endpoints are
|
||||
external installation settings. Pi runs inside `core`; do not install a host Pi executable for
|
||||
the application runtime.
|
||||
## What must be ready
|
||||
|
||||
Secrets, certificates, Pi authentication, and workspace endpoint bindings are protected
|
||||
installation-local files. Never put them in a workspace descriptor, an env file intended for
|
||||
version control, a URL, or a command line.
|
||||
You need Docker with Compose v2, Git, Bash, curl, OpenSSL and shasum. You also need access to the
|
||||
workspace repository and the values supplied by its owner: repository URL/branch, DWH endpoint,
|
||||
database/schema, transport, credentials or certificates, Evidence credentials when applicable,
|
||||
and LLM provider/API-key information.
|
||||
|
||||
## Create the local installation
|
||||
The workspace repository and the THothII application repository are different. A workspace
|
||||
descriptor may declare Evidence, but database passwords and installation bindings are stored in
|
||||
the installation Catalog, not in Git.
|
||||
|
||||
From the repository root, start the interactive setup and select the local profile:
|
||||
## One guided command
|
||||
|
||||
```sh
|
||||
tht setup --profile local
|
||||
```
|
||||
After cloning THothII, checking prerequisites and installing tht, run:
|
||||
|
||||
It writes the selected non-secret descriptor below `deploy/<installation-id>/`, the associated
|
||||
operator env file, and can create protected secret templates. Keep the descriptor path: pass it
|
||||
to commands as `--installation /absolute/path/thothii-installation.yaml` when more than one
|
||||
installation can be discovered.
|
||||
~~~
|
||||
tht setup --complete --profile local --shell-mode full --shell-default-locale en
|
||||
~~~
|
||||
|
||||
If the descriptor is prepared manually instead, begin with
|
||||
[`thothii-installation.local.yaml`](examples/thothii-installation.local.yaml), set mode `0600` or
|
||||
`0400`, and ensure `THT_INSTALLATION_CONFIG_SOURCE` in the selected env file points to that exact
|
||||
file. Create the secret bundle from `deploy/secrets/thothii.secrets.example`, protect it, and set
|
||||
the file locations and external endpoints in the env file. The required settings include:
|
||||
The first run creates protected placeholders under deploy/local/secrets/. Fill the required
|
||||
credential files and rerun the same command. The command validates the local files and paths,
|
||||
renders Compose, builds the images, starts catalog-db, runs catalog-migrate, starts the full
|
||||
stack, and pulls/activates the workspace repository. Evidence source files declared by the
|
||||
workspace are imported during activation.
|
||||
|
||||
- `PI_AUTH_FILE`, `THT_SECRETS_FILE`, and the catalog password source files;
|
||||
- `THT_INSTALLATION_CONFIG_SOURCE` and the workspace Git remote/branch;
|
||||
- the DWH and model-provider endpoints; and
|
||||
- `THT_AUTH_CONFIG_ROOT` for local authentication or the OIDC configuration selected during setup.
|
||||
For an already configured installation:
|
||||
|
||||
For the supported secret names and the metadata-generation model credential boundary, see the
|
||||
`deploy/secrets/README.md` file in the installation checkout. It is intentionally not published
|
||||
as a documentation page because it describes a protected local-file contract.
|
||||
|
||||
## Start and verify
|
||||
|
||||
For the normal local path, use the launcher:
|
||||
|
||||
```sh
|
||||
./scripts/run-stack.sh
|
||||
```
|
||||
|
||||
It builds `core`, starts `catalog-db`, runs `catalog-migrate`, then keeps the base plus local
|
||||
Compose profile in the foreground. Database migrations are deliberately not a hidden backend
|
||||
startup action. Open `http://127.0.0.1:8080` unless `THOTH_HTTP_PORT` was changed.
|
||||
|
||||
In another terminal, verify the installation without changing it:
|
||||
|
||||
```sh
|
||||
tht --installation /absolute/path/thothii-installation.yaml doctor --json
|
||||
~~~
|
||||
tht --installation /absolute/path/thothii-installation.yaml status
|
||||
```
|
||||
tht --installation /absolute/path/thothii-installation.yaml doctor --json
|
||||
tht --installation /absolute/path/thothii-installation.yaml workspace test --json
|
||||
~~~
|
||||
|
||||
`/health` verifies application-process readiness; `tht doctor` is the diagnostic surface for
|
||||
Compose, configuration, workspace, workflow, and Pi prerequisites.
|
||||
doctor --json is the non-destructive general core test. workspace test also probes the configured
|
||||
database, Evidence, Qdrant and embedding service for every active workspace. It requires the
|
||||
workspace database to have been configured in Database Management first.
|
||||
|
||||
## Routine lifecycle and next steps
|
||||
## Installer-only completion
|
||||
|
||||
Use `tht start [--build]`, `tht stop`, `tht logs`, and `tht doctor` rather than composing ad-hoc
|
||||
container commands. Named volumes retain settings, Pi state, workspace registry, sessions,
|
||||
Qdrant data, and embedding models across `docker compose down`; removing them requires the
|
||||
explicit destructive `--volumes` form.
|
||||
The installer must still decide which LLMs and API keys are approved, configure and test each
|
||||
workspace database, synchronize its schema, generate and consolidate descriptions, create Qdrant
|
||||
entries, review naming-based FK suggestions alongside schema FKs, and load the approved
|
||||
relationships. The final declaration of completeness requires green doctor and workspace test
|
||||
results plus one real natural-language question completed through final SQL.
|
||||
|
||||
After the stack is healthy, configure authentication if setup did not do so, then continue with
|
||||
[Workspace operations](../operations/workspaces.md). For server profile, reverse proxy, backups,
|
||||
and recovery, use the deployment program and its manual gates; the server profile is not a
|
||||
drop-in replacement for the local command above.
|
||||
Migrations are part of setup --complete. Do not mix this installation’s descriptor or volumes with
|
||||
a different Compose environment. Preserve the descriptor, credentials, Catalog and persistent
|
||||
volumes; do not use docker compose down --volumes as a routine stop.
|
||||
|
||||
See the guides for the Windows/macOS/Linux prerequisite matrix, workspace repository explanation,
|
||||
secret layout and Gate A/Gate B acceptance checks.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Display mode and language
|
||||
|
||||
ThothII can run with its own application header (**full**) or inside an integrated
|
||||
portal (**embedded**). Display mode and authentication are separate choices.
|
||||
|
||||
| Installation | Display | Authentication |
|
||||
| --- | --- | --- |
|
||||
| Standalone local instance | `full` | Local ThothII account |
|
||||
| Standalone server | `full` | Local accounts or configured OIDC provider |
|
||||
| Integrated portal | `embedded` | Identity verified by the portal's trusted server proxy |
|
||||
|
||||
## Standalone setup
|
||||
|
||||
Follow the complete [Italian](standalone-manual-it.md) or
|
||||
[English](standalone-manual-en.md) installation procedure. It explicitly selects
|
||||
`--shell-mode full --shell-default-locale en` and separates configuration, credentials,
|
||||
initial migrations and startup. Do not skip those steps by running setup alone.
|
||||
|
||||
The authored installation descriptor contains:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: full
|
||||
defaultLocale: en
|
||||
```
|
||||
|
||||
Use `it` for an Italian initial interface. Existing browser language preferences can
|
||||
override that initial value. Full mode remembers language and theme in the browser.
|
||||
|
||||
For an existing installation, preserve the current descriptor and edit only the intended
|
||||
settings; do not rerun setup to overwrite it. With a current host `tht` binary:
|
||||
|
||||
```sh
|
||||
tht --installation /absolute/path/thothii-installation.yaml installation generate
|
||||
tht --installation /absolute/path/thothii-installation.yaml start
|
||||
tht --installation /absolute/path/thothii-installation.yaml status
|
||||
tht --installation /absolute/path/thothii-installation.yaml doctor --json
|
||||
```
|
||||
|
||||
Generation updates derived configuration; it does not start services. `start` applies
|
||||
the installation's normal lifecycle and is not guaranteed to touch only the frontend.
|
||||
Follow the deployment's maintenance procedure and retain its network, authentication and
|
||||
model settings. Do not edit generated files or remove persistent volumes.
|
||||
|
||||
## Authentication and embedded deployments
|
||||
|
||||
Full mode does not configure login by itself. See [local authentication](authentication-local.md)
|
||||
or [OIDC](authentication-oidc.md), with [Authentik](authentik.md) as a provider option.
|
||||
|
||||
Embedded mode requires a compatible portal integration, not just a descriptor toggle.
|
||||
The portal owns login/logout and supplies a server-verified identity. A presentation
|
||||
adapter does not authenticate users. The core must not be reachable by a route that
|
||||
bypasses the trusted proxy. Do not add a second OIDC login to an already authenticated
|
||||
upstream deployment.
|
||||
|
||||
Portal implementation details belong to the
|
||||
[developer integration reference in the repository](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/install/authentication-upstream.md),
|
||||
not to the standalone installation procedure.
|
||||
|
||||
## Three different languages
|
||||
|
||||
- **Interface language** controls labels, forms and application messages.
|
||||
- **Session interaction language** is captured when a session is created. Resuming it
|
||||
retains that language even if the interface language changes later.
|
||||
- **Workspace language** concerns domain content and retrieval; switching the interface
|
||||
does not translate Evidence, SQL, identifiers or database values.
|
||||
|
||||
In embedded mode the interface follows the portal's language and theme. A portal language
|
||||
change may reload the page. Saved session artifacts remain available, but resuming work
|
||||
is explicit; a reload does not by itself request a new model generation.
|
||||
@@ -0,0 +1,256 @@
|
||||
# Guided standalone installation
|
||||
|
||||
[Versione italiana](standalone-manual-it.md)
|
||||
|
||||
This is the fresh-machine installation procedure for THothII. THothII receives a natural-language
|
||||
question, queries an enterprise database read-only, and guides the user through SQL review. The
|
||||
core, PostgreSQL catalog, Qdrant, embedding service, and Pi run in Docker; Node.js, Python, and Pi
|
||||
are not required on the host.
|
||||
|
||||
## Before you start: the two repositories
|
||||
|
||||
There are two separate repositories:
|
||||
|
||||
1. the application repository cloned by the user:
|
||||
https://git.tylconsulting.it/mptyl/ThothII.git;
|
||||
2. the workspace repository supplied by the curator/installer. It is not the THothII repository
|
||||
and must not be cloned inside the application directory.
|
||||
|
||||
The workspace repository normally contains:
|
||||
|
||||
~~~
|
||||
thoth-workspaces.yaml
|
||||
<workspace-id>/workspace.yaml
|
||||
<workspace-id>/evidence/** # when Evidence is declared
|
||||
~~~
|
||||
|
||||
workspace.yaml contains workspace identity, language and optional Evidence source. By design it does
|
||||
not contain database passwords. Database identity, transport (PostgreSQL, REST, or tunnel), user,
|
||||
password, token and certificates are installation-local settings stored encrypted by the Catalog.
|
||||
This prevents credentials from being committed to the workspace repository.
|
||||
|
||||
## 0. Machine prerequisites
|
||||
|
||||
### Windows
|
||||
|
||||
- Windows 10/11 with Docker Desktop running and the WSL2 backend enabled.
|
||||
- Ubuntu in WSL2, with Docker Desktop integration enabled for that distribution.
|
||||
- Git, Bash, curl, OpenSSL and shasum inside WSL2.
|
||||
- Do not install Node.js, Python or Pi on the host for this procedure.
|
||||
|
||||
If WSL2 is not installed, use the company procedure or, in PowerShell:
|
||||
|
||||
~~~
|
||||
wsl --install -d Ubuntu
|
||||
~~~
|
||||
|
||||
Run all commands inside Ubuntu WSL2, in a Linux directory such as $HOME/src, not under /mnt/c.
|
||||
scripts/install-tht.ps1 exists for advanced native PowerShell scenarios; use WSL2 for the
|
||||
reproducible test.
|
||||
|
||||
### macOS
|
||||
|
||||
- Docker Desktop installed and running, with several GB free for images and the embedding model.
|
||||
- Git, Bash, curl, OpenSSL and shasum.
|
||||
- Intel and Apple Silicon Macs are supported when Docker Desktop supports the architecture
|
||||
reported by the Docker server.
|
||||
- Do not install Node.js, Python or Pi on the host for this procedure.
|
||||
|
||||
### Linux, including Omarchy
|
||||
|
||||
- Git, Bash, curl, OpenSSL and shasum.
|
||||
- Docker Engine and the Docker Compose v2 plugin. On Omarchy, check first:
|
||||
|
||||
~~~
|
||||
command -v docker
|
||||
docker compose version
|
||||
docker info
|
||||
~~~
|
||||
|
||||
If Docker is missing, install Docker and Compose using the distribution-approved package procedure,
|
||||
then start the service. On an Arch-like distribution the typical route is:
|
||||
|
||||
~~~
|
||||
sudo pacman -S docker docker-compose
|
||||
sudo systemctl enable --now docker
|
||||
sudo usermod -aG docker "$USER"
|
||||
~~~
|
||||
|
||||
After adding the group, open a new session and repeat docker info. Node.js, Python and Pi are not
|
||||
needed on the host: they are in the Docker images.
|
||||
|
||||
On every system run:
|
||||
|
||||
~~~
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
docker version --format '{{.Server.Arch}}'
|
||||
~~~
|
||||
|
||||
The architecture must be amd64, x86_64, arm64, or aarch64. You also need access to the
|
||||
application Gitea repository, the workspace repository URL/branch and credentials, container
|
||||
reachability to DWH/LLM endpoints, and the credentials, tokens or certificates associated with
|
||||
the databases.
|
||||
|
||||
## 1. What to clone
|
||||
|
||||
Clone only the application:
|
||||
|
||||
~~~
|
||||
mkdir -p "$HOME/src"
|
||||
cd "$HOME/src"
|
||||
git clone https://git.tylconsulting.it/mptyl/ThothII.git
|
||||
cd ThothII
|
||||
git rev-parse --short HEAD
|
||||
~~~
|
||||
|
||||
Record the revision. tht setup --complete downloads the workspace repository into a persistent
|
||||
Docker volume using the URL, branch and transport supplied during setup.
|
||||
|
||||
## 2. Install the terminal command
|
||||
|
||||
From the clone root:
|
||||
|
||||
~~~
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
THT_INSTALL_DIRECTORY="$HOME/.local/bin" bash scripts/install-tht.sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
tht version
|
||||
~~~
|
||||
|
||||
tht is the only native component to install. It builds the binary with Docker and orchestrates
|
||||
Compose; it is not a second application runtime.
|
||||
|
||||
## 3. Prepare a few secrets and run complete setup
|
||||
|
||||
The first execution creates protected placeholders under deploy/local/secrets/ and stops if a
|
||||
required credential is missing. Fill in the requested files and rerun the same command; compatible
|
||||
configuration files are reused.
|
||||
|
||||
~~~
|
||||
tht setup --complete --profile local --shell-mode full --shell-default-locale en
|
||||
~~~
|
||||
|
||||
The setup asks only for information the computer cannot know:
|
||||
|
||||
| Request | What to provide |
|
||||
| --- | --- |
|
||||
| Workspace repository | Data/configuration repository URL, not ThothII.git |
|
||||
| Branch | normally main |
|
||||
| Access | ssh with key and known_hosts, or https with credential file and CA |
|
||||
| DWH/LLM URL | endpoint without a token in the URL |
|
||||
| Local login | initial user and password requested by the prompt |
|
||||
|
||||
The setup generates random Catalog passwords and writes their paths, never their values, to
|
||||
operator.env. It runs docker compose config, builds images, starts the Catalog, runs
|
||||
catalog-migrate, starts the stack, and pulls the workspace repository. The pull also activates
|
||||
declared Evidence; at minimum source files present in the workspace are materialized locally.
|
||||
|
||||
### The file the user fills in
|
||||
|
||||
The main file is:
|
||||
|
||||
~~~
|
||||
deploy/local/secrets/thothii.secrets
|
||||
~~~
|
||||
|
||||
Add only NAME=VALUE lines needed by modelCatalog and installation adapters, such as an LLM API key
|
||||
(DEEPSEEK_API_KEY, OPENAI_API_KEY, or the key declared by the catalog) and, when applicable,
|
||||
THT_DWH_API_KEY. Allowed names are documented in deploy/secrets/README.md. Never put tokens in
|
||||
URLs, the repository, or copied shell commands.
|
||||
|
||||
Two distinctions prevent common errors:
|
||||
|
||||
- when the catalog uses pi_auth, the LLM token belongs in the Pi pi-auth.json file created by
|
||||
setup; {} is only a placeholder and does not enable a model;
|
||||
- workspace database credentials (PostgreSQL password, REST API token, tunnel SSH key,
|
||||
known_hosts, CA) do not belong in the workspace repository. Enter them per workspace in
|
||||
Database Management, which stores them encrypted in the Catalog. The workspace declares
|
||||
database/schema and transport; the installer must obtain the actual values from the database owner.
|
||||
|
||||
A private workspace repository also needs the Git files required by its transport: an SSH key and
|
||||
known_hosts, or an HTTPS credential file and CA. These are transport files, not a second bundle to
|
||||
commit. To minimize manual files, use SSH with an already-authorized deploy key.
|
||||
|
||||
## 4. Automatic checks and terminal tests
|
||||
|
||||
Setup verifies files, permissions, descriptor, Compose, Docker, authentication, services, Pi and
|
||||
the workspace. After startup, run these commands at any time:
|
||||
|
||||
~~~
|
||||
INSTALLATION="$PWD/deploy/local/thothii-installation.yaml"
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" workspace pull --json
|
||||
tht --installation "$INSTALLATION" workspace test --json
|
||||
~~~
|
||||
|
||||
workspace test checks, for every active workspace, database binding and credentials, Evidence,
|
||||
Qdrant, and the embedding service. It exits non-zero when the database binding is missing or a
|
||||
connection is unusable. Before running it, the installer must configure the database in Database
|
||||
Management: the workspace repository cannot contain the password by itself.
|
||||
|
||||
doctor --json is the repeatable, non-destructive core verification. The final functional test must
|
||||
also open http://127.0.0.1:8080, sign in, and complete a real question through final SQL.
|
||||
|
||||
## Activities only the installer can complete
|
||||
|
||||
The procedure automates bootstrap, but it cannot invent enterprise decisions or authorizations.
|
||||
The installer must complete and record:
|
||||
|
||||
1. usable LLMs, the modelCatalog, and linked API keys; then run tht pi test and tht doctor;
|
||||
2. database configuration, connection test, schema synchronization, and description generation;
|
||||
3. human consolidation of generated descriptions;
|
||||
4. Qdrant semantic entries through workspace preprocess run;
|
||||
5. naming-based FK suggestions as a complement to schema FKs, human review, and loading approved
|
||||
relationships into Qdrant;
|
||||
6. recurring tht doctor --json and tht workspace test --json checks;
|
||||
7. one real question completed successfully without connection or model errors.
|
||||
|
||||
Configuration is complete only when all applicable activities are done, decisions are recorded, and
|
||||
the two terminal tests are green. The core is usable only after the real question, not merely
|
||||
because the frontend answers /health.
|
||||
|
||||
## Gate A and Gate B
|
||||
|
||||
### Gate A — platform
|
||||
|
||||
~~~
|
||||
uname -a
|
||||
docker version --format '{{.Server.Version}} {{.Server.Arch}}'
|
||||
tht version
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
bash scripts/verify-standalone-install.sh "$INSTALLATION"
|
||||
~~~
|
||||
|
||||
### Gate B — usability
|
||||
|
||||
~~~
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" workspace test --json
|
||||
curl --fail --silent --show-error http://127.0.0.1:8080/health
|
||||
~~~
|
||||
|
||||
Then run a real question and stop/restart with tht stop and tht start. Do not use docker compose
|
||||
down --volumes: it deletes the Catalog, sessions, Qdrant data and the embedding model.
|
||||
|
||||
## Quick diagnosis
|
||||
|
||||
| Symptom | Action |
|
||||
| --- | --- |
|
||||
| Docker Engine is not reachable | start Docker Desktop or systemctl and repeat docker info |
|
||||
| Omarchy cannot find docker | install Docker/Compose, enable the service and open a new session |
|
||||
| Windows sees Docker but Bash fails | use Ubuntu WSL2 and enable its Docker Desktop integration |
|
||||
| workspace pull fails | check URL, branch, key/credential file and known_hosts from the container |
|
||||
| workspace test reports a missing binding | configure database, token/password and CA in Database Management |
|
||||
| Pi is not ready | fill pi-auth.json or the key declared by modelCatalog, then run tht pi test |
|
||||
|
||||
## Related documents
|
||||
|
||||
- [Install and first start](first-start.md)
|
||||
- [Workspace operations](../operations/workspaces.md)
|
||||
- [Database Management](../operations/database-management.md)
|
||||
- [Model configuration](../general/pi-configuration.md)
|
||||
- deploy/secrets/README.md
|
||||
|
||||
Publishing images on Docker Hub and native DMG/MSI/AppImage installers remain later work: this
|
||||
procedure starts from the Gitea clone and does not require pre-published Docker Hub images.
|
||||
@@ -0,0 +1,262 @@
|
||||
# Installazione standalone guidata
|
||||
|
||||
[English version](standalone-manual-en.md)
|
||||
|
||||
Questa è la procedura per installare THothII da zero. THothII riceve una domanda in linguaggio
|
||||
naturale, interroga in sola lettura un database aziendale e accompagna l’utente nella revisione
|
||||
della SQL risultante. Il core, il catalogo PostgreSQL, Qdrant, il servizio di embedding e Pi vengono
|
||||
eseguiti in Docker; sul computer non servono Node.js, Python o Pi.
|
||||
|
||||
## Prima di iniziare: i due repository
|
||||
|
||||
Servono due repository distinti:
|
||||
|
||||
1. il repository dell’applicazione, che l’utente clona:
|
||||
https://git.tylconsulting.it/mptyl/ThothII.git;
|
||||
2. il repository dei workspace, indicato dal curatore/installatore. Non è il repository di
|
||||
THothII e non va clonato manualmente nella directory dell’applicazione.
|
||||
|
||||
Il repository workspace contiene il catalogo e una directory per ogni workspace, normalmente:
|
||||
|
||||
~~~
|
||||
thoth-workspaces.yaml
|
||||
<workspace-id>/workspace.yaml
|
||||
<workspace-id>/evidence/** # se il workspace dichiara Evidence
|
||||
~~~
|
||||
|
||||
Il file workspace.yaml descrive identità, lingua e, opzionalmente, la sorgente Evidence. Per scelta
|
||||
architetturale non contiene password del database. L’identità del database, il trasporto
|
||||
(PostgreSQL, REST o tunnel), username, password, token e certificati sono configurazione locale
|
||||
dell’installazione, conservata cifrata dal Catalog. Questo evita di committare credenziali nel
|
||||
repository workspace.
|
||||
|
||||
## 0. Prerequisiti della macchina
|
||||
|
||||
### Windows
|
||||
|
||||
- Windows 10/11 con Docker Desktop avviato e backend WSL2 abilitato.
|
||||
- Ubuntu in WSL2, con integrazione Docker Desktop abilitata per quella distribuzione.
|
||||
- Git, Bash, curl, OpenSSL e shasum nella distribuzione WSL2.
|
||||
- Non installare Node.js, Python o Pi sull’host per questa procedura.
|
||||
|
||||
In PowerShell, se WSL2 non esiste ancora, usare la procedura aziendale oppure:
|
||||
|
||||
~~~
|
||||
wsl --install -d Ubuntu
|
||||
~~~
|
||||
|
||||
Eseguire poi tutti i comandi dentro Ubuntu WSL2, in una directory Linux come $HOME/src, non sotto
|
||||
/mnt/c. Il percorso nativo scripts/install-tht.ps1 esiste per scenari PowerShell avanzati; per la
|
||||
prova riproducibile usare WSL2.
|
||||
|
||||
### macOS
|
||||
|
||||
- Docker Desktop installato, avviato e con alcuni GB liberi per immagini e modello di embedding.
|
||||
- Git, Bash, curl, OpenSSL e shasum.
|
||||
- Sono supportati Mac Intel e Apple Silicon se Docker Desktop supporta l’architettura restituita
|
||||
dal Docker server.
|
||||
- Non installare Node.js, Python o Pi sull’host per questa procedura.
|
||||
|
||||
### Linux, incluso Omarchy
|
||||
|
||||
- Git, Bash, curl, OpenSSL e shasum.
|
||||
- Docker Engine e il plugin Docker Compose v2. Su Omarchy verificare prima:
|
||||
|
||||
~~~
|
||||
command -v docker
|
||||
docker compose version
|
||||
docker info
|
||||
~~~
|
||||
|
||||
Se Docker manca, installare Docker e Compose con il gestore pacchetti/procedura approvata dalla
|
||||
distribuzione, poi avviare il servizio. Su una distribuzione Arch-like il percorso tipico è:
|
||||
|
||||
~~~
|
||||
sudo pacman -S docker docker-compose
|
||||
sudo systemctl enable --now docker
|
||||
sudo usermod -aG docker "$USER"
|
||||
~~~
|
||||
|
||||
Dopo l’aggiunta al gruppo aprire una nuova sessione e ripetere docker info. Non installare Node.js,
|
||||
Python o Pi sull’host: sono dentro le immagini Docker.
|
||||
|
||||
Su tutti i sistemi il controllo finale è:
|
||||
|
||||
~~~
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
docker version --format '{{.Server.Arch}}'
|
||||
~~~
|
||||
|
||||
L’architettura deve essere amd64, x86_64, arm64 o aarch64. Servono inoltre accesso al repository
|
||||
Gitea dell’applicazione, URL/branch e credenziali del repository workspace, raggiungibilità dal
|
||||
container degli endpoint DWH/LLM e le credenziali, token o certificati associati ai database.
|
||||
|
||||
## 1. Cosa clonare
|
||||
|
||||
Clonare solo l’applicazione:
|
||||
|
||||
~~~
|
||||
mkdir -p "$HOME/src"
|
||||
cd "$HOME/src"
|
||||
git clone https://git.tylconsulting.it/mptyl/ThothII.git
|
||||
cd ThothII
|
||||
git rev-parse --short HEAD
|
||||
~~~
|
||||
|
||||
Annotare la revisione. Il repository workspace verrà scaricato da tht setup --complete dentro un
|
||||
volume Docker persistente, usando URL, branch e trasporto indicati durante il setup.
|
||||
|
||||
## 2. Installare il comando terminale
|
||||
|
||||
Dal root del clone:
|
||||
|
||||
~~~
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
THT_INSTALL_DIRECTORY="$HOME/.local/bin" bash scripts/install-tht.sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
tht version
|
||||
~~~
|
||||
|
||||
Il comando tht è l’unico componente nativo da installare. Costruisce il binario con Docker e
|
||||
orchestra Compose; non è un secondo runtime dell’applicazione.
|
||||
|
||||
## 3. Preparare pochi segreti e avviare il setup completo
|
||||
|
||||
La prima esecuzione crea i placeholder protetti sotto deploy/local/secrets/ e si ferma se manca
|
||||
una credenziale necessaria. Compilare i file indicati e rilanciare lo stesso comando: i file di
|
||||
configurazione già compatibili vengono riutilizzati.
|
||||
|
||||
~~~
|
||||
tht setup --complete --profile local --shell-mode full --shell-default-locale en
|
||||
~~~
|
||||
|
||||
Durante il setup servono solo le informazioni operative che il computer non può conoscere:
|
||||
|
||||
| Richiesta | Cosa inserire |
|
||||
| --- | --- |
|
||||
| Repository workspace | URL del repository dati/configurazione, non ThothII.git |
|
||||
| Branch | normalmente main |
|
||||
| Accesso | ssh con chiave e known_hosts, oppure https con credential file e CA |
|
||||
| DWH/LLM URL | endpoint senza token nella URL |
|
||||
| Login locale | utente e password iniziale richiesti dal prompt |
|
||||
|
||||
Il setup crea automaticamente le password casuali del Catalog e le scrive in operator.env come
|
||||
percorsi, non come valori. Esegue docker compose config, costruisce le immagini, avvia il Catalog,
|
||||
esegue catalog-migrate, avvia lo stack e importa il repository workspace. L’import attiva anche
|
||||
l’Evidence dichiarata: almeno i file source presenti nel workspace vengono materializzati nel
|
||||
registro locale.
|
||||
|
||||
### Il file da compilare
|
||||
|
||||
Il file principale è:
|
||||
|
||||
~~~
|
||||
deploy/local/secrets/thothii.secrets
|
||||
~~~
|
||||
|
||||
Inserire solo righe NOME=VALORE necessarie al modelCatalog e agli adapter, per esempio una API key
|
||||
LLM (DEEPSEEK_API_KEY, OPENAI_API_KEY o quella dichiarata dal catalogo) ed eventualmente
|
||||
THT_DWH_API_KEY. I nomi ammessi sono documentati in deploy/secrets/README.md. Non mettere token
|
||||
nelle URL, nel repository o nei comandi.
|
||||
|
||||
Due precisazioni evitano gli errori più comuni:
|
||||
|
||||
- se il catalogo usa pi_auth, il token LLM va nel file Pi pi-auth.json creato dal setup; {} è solo
|
||||
un placeholder e non abilita alcun modello;
|
||||
- le credenziali specifiche di un database workspace (password PostgreSQL, API token REST, chiave
|
||||
SSH del tunnel, known_hosts, CA) non vanno nel repository workspace: si inseriscono per workspace
|
||||
in Database Management, che le conserva nel Catalog cifrato. Il workspace indica database/schema
|
||||
e trasporto; l’installatore deve ottenere dal proprietario il valore corretto.
|
||||
|
||||
Per un repository workspace privato sono inoltre indispensabili i file Git richiesti dal trasporto:
|
||||
una chiave SSH e known_hosts, oppure credential file HTTPS e CA. Sono file di trasporto, non un
|
||||
secondo bundle da committare. Per ridurre i file da compilare, usare SSH con una deploy key già
|
||||
autorizzata.
|
||||
|
||||
## 4. Controlli automatici e test da terminale
|
||||
|
||||
Il setup verifica file, permessi, descriptor, Compose, Docker, autenticazione, servizi, Pi e
|
||||
workspace. Dopo l’avvio usare questi comandi in qualunque momento:
|
||||
|
||||
~~~
|
||||
INSTALLATION="$PWD/deploy/local/thothii-installation.yaml"
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" workspace pull --json
|
||||
tht --installation "$INSTALLATION" workspace test --json
|
||||
~~~
|
||||
|
||||
workspace test prova, per ogni workspace attivo, il binding del database e le credenziali, Evidence,
|
||||
Qdrant e il servizio embedding. Restituisce exit code diverso da zero se manca il binding del
|
||||
database o una connessione non è utilizzabile. Prima di eseguirlo l’installatore deve aver
|
||||
configurato il database in Database Management: il workspace repository da solo non può contenere
|
||||
la password.
|
||||
|
||||
Per una verifica generale del core, doctor --json è il test ripetibile e non distruttivo. Il test
|
||||
funzionale finale deve inoltre aprire http://127.0.0.1:8080, autenticarsi e completare una domanda
|
||||
reale fino alla SQL finale.
|
||||
|
||||
## Attività che può svolgere solo l’installatore
|
||||
|
||||
La procedura automatizza il bootstrap, non può inventare decisioni o autorizzazioni aziendali.
|
||||
L’installatore deve completare e registrare:
|
||||
|
||||
1. quali LLM sono utilizzabili, il relativo modelCatalog e le API key collegate; poi eseguire
|
||||
tht pi test e tht doctor;
|
||||
2. per ogni database: configurazione, test connessione, sincronizzazione dello schema e
|
||||
generazione delle descrizioni;
|
||||
3. consolidamento umano delle descrizioni generate;
|
||||
4. generazione delle entry semantiche in Qdrant tramite workspace preprocess run;
|
||||
5. generazione delle FK suggerite dal naming, come complemento alle FK lette dallo schema, revisione
|
||||
umana delle proposte e caricamento delle relazioni approvate in Qdrant;
|
||||
6. verifica periodica con tht doctor --json e tht workspace test --json;
|
||||
7. una domanda reale completata con successo, senza errori di connessione o modello.
|
||||
|
||||
La configurazione è dichiarata completa solo quando tutti i punti applicabili sono stati eseguiti,
|
||||
le decisioni sono state registrate e i due test terminali sono verdi. Il core è dichiarato usabile
|
||||
solo dopo la domanda reale, non perché il frontend risponde a /health.
|
||||
|
||||
## Gate A e Gate B
|
||||
|
||||
### Gate A — piattaforma
|
||||
|
||||
~~~
|
||||
uname -a
|
||||
docker version --format '{{.Server.Version}} {{.Server.Arch}}'
|
||||
tht version
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
bash scripts/verify-standalone-install.sh "$INSTALLATION"
|
||||
~~~
|
||||
|
||||
### Gate B — usabilità
|
||||
|
||||
~~~
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" workspace test --json
|
||||
curl --fail --silent --show-error http://127.0.0.1:8080/health
|
||||
~~~
|
||||
|
||||
Poi eseguire una domanda reale e fermare/riavviare con tht stop e tht start. Non usare docker
|
||||
compose down --volumes: cancella Catalog, sessioni, Qdrant e il modello embedding.
|
||||
|
||||
## Diagnosi rapida
|
||||
|
||||
| Sintomo | Azione |
|
||||
| --- | --- |
|
||||
| Docker Engine is not reachable | avviare Docker Desktop o systemctl e ripetere docker info |
|
||||
| Omarchy non trova docker | installare Docker/Compose, abilitare il servizio e riaprire la sessione |
|
||||
| Windows vede Docker ma Bash fallisce | usare Ubuntu WSL2 e abilitarne l’integrazione in Docker Desktop |
|
||||
| pull workspace fallisce | controllare URL, branch, chiave/credential file e known_hosts dal container |
|
||||
| workspace test segnala binding mancante | configurare database, token/password e CA in Database Management |
|
||||
| Pi non è pronto | compilare pi-auth.json o la chiave dichiarata dal modelCatalog, poi eseguire tht pi test |
|
||||
|
||||
## Documenti collegati
|
||||
|
||||
- [Installazione e primo avvio](first-start.md)
|
||||
- [Operazioni sui workspace](../operations/workspaces.md)
|
||||
- [Database Management](../operations/database-management.md)
|
||||
- [Configurazione dei modelli](../general/pi-configuration.md)
|
||||
- deploy/secrets/README.md
|
||||
|
||||
La pubblicazione di immagini su Docker Hub e gli installer nativi DMG/MSI/AppImage restano attività
|
||||
successive: questa procedura parte dal clone Gitea e non richiede immagini Docker Hub pre-pubblicate.
|
||||
@@ -1,129 +0,0 @@
|
||||
# Docker installation in the current operating contexts
|
||||
|
||||
ThothII uses one Compose topology:
|
||||
|
||||
- `frontend`
|
||||
- `core`
|
||||
- `catalog-db`
|
||||
- `qdrant`
|
||||
- `embedding`
|
||||
- `embedding-model-init`
|
||||
- `catalog-migrate` (one-shot)
|
||||
|
||||
Qdrant and Ollama embedding are required internal Compose services. Only DWH and the LLM remain
|
||||
external. The fixed model is `qwen3-embedding:0.6b` with 1024 dimensions and cosine distance;
|
||||
`embedding-model-init` prepares it before `core` starts.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
INSTALL["Installation descriptor"] --> CONTEXT{Context}
|
||||
CONTEXT --> LOCAL["Local\nCompose local"]
|
||||
CONTEXT --> SERVER["Server\nCompose server"]
|
||||
CONTEXT --> SESSION["Session server\noperator services"]
|
||||
CONTEXT --> AUTH["Auth runtime\nprojection services"]
|
||||
LOCAL --> BUNDLE["Common secret bundle"]
|
||||
SERVER --> BUNDLE
|
||||
SESSION --> BUNDLE
|
||||
AUTH --> BUNDLE
|
||||
BUNDLE --> SERVICES["Frontend, core, catalog DB, vector, embedding"]
|
||||
```
|
||||
|
||||
## Short ownership contract
|
||||
|
||||
| Componente | Ownership | Contratto operativo |
|
||||
| --- | --- | --- |
|
||||
| DWH | External | External endpoint configured by the installation. |
|
||||
| LLM | External | Endpoint or policy outside the internal semantic infrastructure. |
|
||||
| Qdrant | Internal | Required internal Compose service with persistent `qdrant-data` volume. |
|
||||
| Ollama embedding | Internal | Required internal Compose service for `qwen3-embedding:0.6b`. |
|
||||
|
||||
## Local path: setup, migration, start
|
||||
|
||||
The normal local path is [Install and first start](install/first-start.md). It uses `tht setup`
|
||||
to create the selected installation-local descriptor and runs the catalog migration explicitly
|
||||
before application startup.
|
||||
|
||||
If an operator intentionally prepares the descriptor and protected files by hand, the equivalent
|
||||
foreground launch is:
|
||||
|
||||
```sh
|
||||
cp deploy/env/local.env.example deploy/env/local.env
|
||||
cp deploy/secrets/thothii.secrets.example deploy/secrets/thothii.secrets
|
||||
chmod 600 deploy/secrets/thothii.secrets
|
||||
|
||||
# Copy docs/install/examples/thothii-installation.local.yaml to a protected operator path,
|
||||
# replace every placeholder, chmod it 600, then set that exact path as
|
||||
# THT_INSTALLATION_CONFIG_SOURCE in deploy/env/local.env.
|
||||
|
||||
./scripts/run-stack.sh
|
||||
```
|
||||
|
||||
Set these values in `deploy/env/local.env`:
|
||||
|
||||
- `PI_AUTH_FILE`
|
||||
- `THT_SECRETS_FILE`
|
||||
- `THT_INSTALLATION_CONFIG_SOURCE` (the exact protected host `thothii-installation.yaml`)
|
||||
- `THT_WORKSPACE_GIT_REMOTE`
|
||||
- DWH endpoint
|
||||
- LLM endpoint
|
||||
|
||||
Do not put secrets in `.env`. Runtime secrets belong in the
|
||||
`deploy/secrets/thothii.secrets` bundle.
|
||||
|
||||
## Secret bundle
|
||||
|
||||
The documented and supported bundle keys are:
|
||||
|
||||
```dotenv
|
||||
THT_MODEL_API_KEY=...
|
||||
THT_DWH_API_KEY=...
|
||||
OPENAI_API_KEY=...
|
||||
```
|
||||
|
||||
`THT_MODEL_API_KEY` is available only as an explicitly declared catalog bundle key. A
|
||||
metadata-generation provider references one audited bundle name from `deploy/secrets/README.md`
|
||||
through `modelCatalog.providers.<provider>.authentication.apiKeyEnv`.
|
||||
`apiKeyEnv` may be omitted only for an explicit endpoint that accepts unauthenticated requests;
|
||||
hosted/default endpoints remain keyed.
|
||||
Provider/model/endpoint settings stay in the protected installation descriptor; raw keys do not.
|
||||
|
||||
Compose mounts exactly `THT_INSTALLATION_CONFIG_SOURCE` into `core` as a read-only config and sets
|
||||
the backend-only runtime path `THT_INSTALLATION_CONFIG_FILE` to
|
||||
`/run/thothii-installation/thothii-installation.yaml`. Do not set the runtime path in the host env.
|
||||
Descriptor and bundle changes are loaded only after application restart.
|
||||
|
||||
A private PEM CA remains outside the bundle and must be mounted through a reviewed Compose override.
|
||||
|
||||
## Preprocessing
|
||||
|
||||
Preprocessing runs through the native host CLI and the installation descriptor:
|
||||
|
||||
```sh
|
||||
tht --installation /percorso/assoluto/thothii-installation.yaml \
|
||||
workspace preprocess run --workspace <workspace-id>
|
||||
```
|
||||
|
||||
Per rimuovere soltanto gli indici e gli artifact ricostruibili, preservando Memory e domande risolte:
|
||||
|
||||
```sh
|
||||
tht --installation /percorso/assoluto/thothii-installation.yaml \
|
||||
workspace preprocess clear --workspace <workspace-id>
|
||||
```
|
||||
|
||||
The CLI runs the profile-gated `workspace-maintenance` service. See the
|
||||
[preprocessing contract](contracts/workspace-preprocessing-cli.md) and the
|
||||
[Evidence guide](evidence.md) for details.
|
||||
|
||||
## Server
|
||||
|
||||
For server installations, use the server profile with the session overlay:
|
||||
|
||||
```sh
|
||||
docker compose --env-file deploy/env/server.env \
|
||||
-f compose.yaml -f deploy/compose.server.yaml \
|
||||
-f deploy/compose.session-server.yaml.example up --build -d
|
||||
```
|
||||
|
||||
Also see [Workspace operations](operations/workspaces.md). Server deployment, reverse-proxy,
|
||||
backup, and recovery remain manual-gated operations; do not treat the local profile as a server
|
||||
replacement.
|
||||
@@ -0,0 +1,435 @@
|
||||
# Revisione e bonifica della documentazione
|
||||
|
||||
Data: 15 settembre 2026. Baseline: `6a4634dcf1b1df4ad29510a4da371245abd5c666`.
|
||||
Ambito: 121 Markdown e 23 altri file già presenti in `docs/`, navigazione, collegamenti
|
||||
locali, build e verificatori documentali. Il documento conserva la proposta iniziale
|
||||
e registra sotto l'esecuzione successivamente autorizzata dall'utente. È interno,
|
||||
non una pagina del manuale pubblico.
|
||||
|
||||
## Bonifica eseguita dopo approvazione
|
||||
|
||||
Ritirati 35 file dal working tree: 23 Markdown e 12 artefatti visuali generati
|
||||
(otto PNG, due HTML e due JSON). Recuperabili integralmente dalla revisione
|
||||
`5f3a7f5975b96fae1e1cdd0da08b4d60d41064cc`, precedente a questo intervento,
|
||||
mediante `git show REVISIONE:percorso`. Non eliminata né riscritta la storia Git.
|
||||
|
||||
- Dettagli Compose utili consolidati in [riferimento developer](../operations/compose-reference.md);
|
||||
README rinvia alle sole due procedure manuali IT/EN per installazioni nuove.
|
||||
- M1–M3, E1–E3, X1 e i piani Catalog/model già implementati consolidati nel
|
||||
[record di rilascio](../reports/knowledge-archives-release.md). Test storici non
|
||||
presentati come collaudi attuali; estensioni e accettazioni aperte conservate.
|
||||
- Prompt security assorbito nel PRD, senza approvare il progetto di hardening.
|
||||
- Snapshot di progetto riscritto; overview corretta su Catalog, Memory ed Evidence.
|
||||
- Verificatori auth/DWH e fixture riallineati ai documenti attuali: controlli su
|
||||
permessi, diagnostica, segreti, TLS, separazione dei servizi e link. Le simulazioni
|
||||
del vecchio journal scanner, non più presente nei documenti, non sono conservate
|
||||
come finto collaudo del runtime. Le suite applicative non vengono modificate.
|
||||
- Rimandi Markdown verificati; contratti, ADR (anche superati), progetti con
|
||||
decisioni ancora aperte e runbook/report con rollback o accettazione pendente
|
||||
restano nel repository, esclusi dal sito. Non spostati gate in nuove issue né
|
||||
dichiarati chiusi: lo snapshot corrente li rende espliciti. ADR 0019 conservato
|
||||
senza dedurre dal solo nome che tutte le sue estensioni siano implementate.
|
||||
- Pubblicazione effettiva distinta dal branch `pages`; procedura ripetibile nel
|
||||
[runbook del manuale](../operations/public-docs-publication.md).
|
||||
|
||||
File ritirati (percorsi dalla radice):
|
||||
|
||||
- `docs/architecture/thothii-core-sequence.visual-check.1440x900.dark.png`
|
||||
- `docs/architecture/thothii-core-sequence.visual-check.1440x900.light.png`
|
||||
- `docs/architecture/thothii-core-sequence.visual-check.2048x1320.dark.png`
|
||||
- `docs/architecture/thothii-core-sequence.visual-check.2048x1320.light.png`
|
||||
- `docs/architecture/thothii-core-sequence.visual-check.html`
|
||||
- `docs/architecture/thothii-core-sequence.visual-check.json`
|
||||
- `docs/architecture/thothii-runtime.visual-check.1440x900.dark.png`
|
||||
- `docs/architecture/thothii-runtime.visual-check.1440x900.light.png`
|
||||
- `docs/architecture/thothii-runtime.visual-check.2048x1320.dark.png`
|
||||
- `docs/architecture/thothii-runtime.visual-check.2048x1320.light.png`
|
||||
- `docs/architecture/thothii-runtime.visual-check.html`
|
||||
- `docs/architecture/thothii-runtime.visual-check.json`
|
||||
- `docs/installazione-docker-4-contesti.md`
|
||||
- `docs/plans/2026-08-26-metadata-catalog-from-thothai.md`
|
||||
- `docs/plans/2026-08-28-ai-catalog-description-generation-spec.md`
|
||||
- `docs/plans/2026-08-28-ai-catalog-description-generation.md`
|
||||
- `docs/plans/2026-09-02-installation-model-catalog.md`
|
||||
- `docs/plans/2026-09-08-memory-m1-validation.md`
|
||||
- `docs/plans/2026-09-08-security-hardening-resume-prompt.md`
|
||||
- `docs/plans/2026-09-09-archive-repair-x1-validation.md`
|
||||
- `docs/plans/2026-09-09-evidence-e1-validation.md`
|
||||
- `docs/plans/2026-09-09-evidence-e2-validation.md`
|
||||
- `docs/plans/2026-09-09-evidence-e3-validation.md`
|
||||
- `docs/plans/2026-09-09-memory-m2-validation.md`
|
||||
- `docs/plans/2026-09-09-memory-m3-validation.md`
|
||||
- `docs/research/2026-08-23-legacy-thothai-metadata-capabilities.md`
|
||||
- `docs/research/2026-08-23-postgresql-catalog-deployment-constraints.md`
|
||||
- `docs/research/2026-08-23-thothii-metadata-publication-qdrant-seams.md`
|
||||
- `docs/research/2026-09-07-antigravity-gemini-flash-value.md`
|
||||
- `docs/research/2026-09-07-deepseek-harness-terminal.md`
|
||||
- `docs/research/2026-09-07-omp-codex-zcode.md`
|
||||
- `docs/research/2026-09-07-pi-config-vs-oh-my-pi.md`
|
||||
- `docs/research/2026-09-07-zai-coding-plan-cli-quota.md`
|
||||
- `docs/research/2026-09-07-zed-acp-omp-pi.md`
|
||||
- `docs/research/text-to-sql-products.md`
|
||||
|
||||
Le sezioni successive e l'inventario fotografano la revisione iniziale: la presente
|
||||
sezione prevale per le azioni eseguite. Gli altri ritiri sono rinviati finché non
|
||||
si chiudono i relativi gate; non si cancellano documenti solo perché datati.
|
||||
|
||||
## Esito e modifica applicata
|
||||
|
||||
Il sito confondeva quattro funzioni: manuale del prodotto, riferimento del codice,
|
||||
progettazione e diario delle consegne. Il problema non era soltanto la lunghezza della nav:
|
||||
le pagine non elencate potevano comunque essere generate e indicizzate.
|
||||
|
||||
La configurazione ora pubblica soltanto 20 pagine e cinque asset esplicitamente ammessi.
|
||||
Il resto è escluso da HTML, file copiati e indice di ricerca. Le nuove pagine pubbliche
|
||||
sono `product-overview.md`, `install/shell-and-language.md` e `usage/memory.md`;
|
||||
i documenti tecnici da cui sono state ricavate restano intatti nel repository.
|
||||
Home e `install/first-start.md` sono state riscritte per dare un ingresso univoco.
|
||||
Non è stato cancellato alcun documento della baseline.
|
||||
|
||||
`exclude_docs` nega per default la pubblicazione: aggiungere un file a `docs/` non basta
|
||||
più a metterlo online. La build e la pipeline verificano corrispondenza tra nav ed
|
||||
eccezioni, pagine generate, asset e ricerca. I riferimenti tecnici ancora necessari
|
||||
al lettore rinviano esplicitamente ai sorgenti su Gitea, non a pagine interne del sito.
|
||||
|
||||
**Fuori dal manuale non significa privato.** Il repository ThothII è pubblico: questi
|
||||
file e la cronologia restano leggibili su Gitea. Per riservatezza reale occorrerebbe una
|
||||
decisione separata su repository/accessi e sulla storia già pubblicata. Questa bonifica
|
||||
non modifica autorizzazioni, altri repository o l'installazione applicativa.
|
||||
|
||||
## Tre destinazioni, con regole diverse
|
||||
|
||||
| Destinazione | Contenuto | Regola |
|
||||
| --- | --- | --- |
|
||||
| Manuale pubblico | Prodotto, uso, installazione, configurazione, amministrazione | Descrivere ciò che il lettore può fare oggi; distinguere prerequisiti e limiti verificati. |
|
||||
| Riferimento developer | Architettura, contratti, ADR, test ripetibili, integrazione | Conservare nel repository, fuori da MkDocs; un'autorità per ciascun contratto. |
|
||||
| Lavoro temporaneo o storico | Piani attuati, prompt di ripresa, survey, report di singola consegna | Estrarre decisioni, difetti aperti e rollback ancora necessari; poi ritirare dal working tree con Git come archivio. |
|
||||
|
||||
Un file datato non è automaticamente obsoleto. Un contratto con `v3` nel nome non è
|
||||
automaticamente sostituito da un descriptor v4: sono versioni di oggetti diversi.
|
||||
Un ADR superato conserva il motivo della decisione e il collegamento al successore.
|
||||
|
||||
## Rilievi prioritari, con motivazione
|
||||
|
||||
### 1. Percorsi di installazione concorrenti — corretto per il pubblico
|
||||
|
||||
`install/first-start.md` proponeva ancora setup senza `--configure-only` e avvio con
|
||||
`run-stack.sh`, mentre le guide manuali separano segreti, migrazione e avvio per lo
|
||||
stesso descriptor/progetto. Ora è un punto d'ingresso alle due procedure complete,
|
||||
non una terza ricetta. `installazione-docker-4-contesti.md` rimane interno: consolidarne
|
||||
i dettagli ancora esclusivi in una procedura developer di distribuzione, poi ritirarlo.
|
||||
Anche il percorso rapido nel README va riallineato prima di eliminare quei dettagli.
|
||||
|
||||
### 2. Ricerca architetturale presentata come stato corrente — ritirare dopo estrazione
|
||||
|
||||
`research/2026-08-23-thothii-metadata-publication-qdrant-seams.md` dichiara ancora il
|
||||
passaggio catalog-to-core «deferred» e descrive `annotations.yaml` come input corrente.
|
||||
ADR 0016 e gli attuali contratti registrano invece PostgreSQL come autorità per i
|
||||
consumatori del core. Non usarlo per implementare nuovi comportamenti.
|
||||
|
||||
`research/2026-08-23-postgresql-catalog-deployment-constraints.md` dichiara esplicitamente
|
||||
di essere parzialmente superato da ADR 0004. L'inventario legacy ThothAI del 23 agosto
|
||||
è esplicitamente storico. Estrarre soltanto vincoli non già presenti in ADR/contratti;
|
||||
poi eliminare i tre file dal working tree, conservandoli nella storia Git.
|
||||
|
||||
### 3. Decisioni correnti distribuite tra troppi piani — consolidare prima di eliminare
|
||||
|
||||
Per Memory/Evidence convivono piani di famiglia, M1, amministrazione comune, revisione
|
||||
di semplificazione e sette resoconti M1–M3/E1–E3/X1. Conservare gli invarianti nei
|
||||
contratti e gli scenari ripetibili in `testing/`; trasferire i gate non chiusi in issue.
|
||||
Solo dopo si possono ritirare piani e validazioni di incremento.
|
||||
|
||||
`adr/0019-author-evidence-in-app-with-automatic-activation.md` ha un nome che suggerisce
|
||||
editor in-app e attivazione automatica, ma il titolo descrive editor esterni e
|
||||
consolidamento manuale. Contiene anche «Implementation is pending»: non è un affidabile
|
||||
indicatore dello stato di tutte le parti della release. Conservare numero/decisione,
|
||||
correggere metadati e rimandi e distinguere eventuali estensioni ancora pendenti.
|
||||
|
||||
### 4. Report operativi e piani con stato non aggiornato — non cancellare in blocco
|
||||
|
||||
Il report `2026-09-12-ui-visual-review-delivery.md` apre con «non integrata in main»;
|
||||
le integrazioni successive sono documentate altrove. I piani full-shell dicono ancora
|
||||
«deploy server non eseguito», mentre esistono report di rilascio server del 14 settembre.
|
||||
Ciò prova che lo stato è distribuito, non che tutti i collaudi siano conclusi.
|
||||
|
||||
Consolidare report UI del 12–13 settembre in un record di rilascio per versione.
|
||||
Non ritirare i report del 14 settembre né i runbook di upgrade finché rollback,
|
||||
accettazione interattiva e finestra di osservazione non risultano chiusi dall'operatore.
|
||||
`server-handoff-260906-preprocessing-complete.md` va confrontato con il runbook corrente
|
||||
`server-codex-handoff.md`: estrarre eventuali passaggi di preprocessing esclusivi prima
|
||||
di ritirare la consegna datata.
|
||||
|
||||
### 5. Ricerca su strumenti personali estranea al manuale — candidata all'eliminazione
|
||||
|
||||
I sei confronti CLI/editor/provider del 7 settembre (Antigravity, DeepSeek/CyberArk,
|
||||
OMP/Codex/ZCode, Pi/Oh My Pi, quota Z.ai e Zed/ACP) non spiegano un contratto di ThothII.
|
||||
Prezzi, quote e confronti non sono stati riverificati in questa revisione. Proposta:
|
||||
toglierli dal repository del prodotto, mantenendoli in Git o trasferendoli, su scelta
|
||||
del proprietario, a una raccolta personale. Stessa destinazione proposta per
|
||||
`research/text-to-sql-products.md`, che è una ricognizione di mercato.
|
||||
|
||||
Non applicare automaticamente questa regola alla ricerca ERD, relationship e
|
||||
classificatore sensibile: prima verificare se documenta decisioni ancora aperte.
|
||||
|
||||
### 6. Controlli e snapshot già disallineati — debito da correggere
|
||||
|
||||
Due verificatori falliscono su file già assenti nella baseline, non per l'esclusione
|
||||
da MkDocs introdotta qui:
|
||||
|
||||
- `scripts/auth-docs-smoke.sh`: manca `docs/install/local.md`.
|
||||
- `scripts/verify-dwh-auth-docs.sh`: manca `docs/operations/psd-dwh-auth-rollout.md`.
|
||||
|
||||
Le relative suite di fixture conservano la vecchia struttura. Non ricreare documenti
|
||||
obsoleti per far passare i test: aggiornare i controlli ai contratti attuali, mantenendo
|
||||
le verifiche su segreti, modalità di autenticazione e TLS. Questo riallineamento è
|
||||
proposto, non eseguito in questa bonifica editoriale.
|
||||
|
||||
`PROJECT_STATE.md` cita nove percorsi `docs/*.md` non più esistenti, fra cui il programma
|
||||
server PSD del 20 agosto, l'accettazione Evidence del 25 agosto e il rollout dwh-auth.
|
||||
Inoltre accumula consegne anziché restare uno snapshot breve. Riscriverlo come stato
|
||||
attuale, gate aperti e rimandi esistenti. I normali link Markdown relativi dei documenti
|
||||
esistenti non presentano target mancanti nella verifica eseguita: i riferimenti rotti
|
||||
qui citati sono anche percorsi in backtick o imposti dagli script.
|
||||
|
||||
## Proposta operativa in ordine
|
||||
|
||||
0. **Collegare il sito servito al risultato della pipeline:** il controllo remoto descritto
|
||||
sotto ha rilevato una copia statica vecchia. Prima di dichiarare la bonifica online,
|
||||
aggiornare il percorso di pubblicazione sul server con accesso amministrativo verificato.
|
||||
1. **Separazione pubblica:** applicata; niente cancellazioni di sorgenti.
|
||||
2. **Riallineare le autorità:** snapshot, verificatori, ADR 0019, README e stato delle
|
||||
consegne; spostare gate aperti in issue senza marcarli completati.
|
||||
3. **Ritiro a basso rischio, previa approvazione:** confronti personali, ricerca già
|
||||
esplicitamente superata, prompt di ripresa dopo assorbimento nel PRD, output visuali
|
||||
rigenerabili. Controllare prima i riferimenti in tutto il repository.
|
||||
4. **Consolidamento:** piani completati e report incrementali; non perdere criteri di
|
||||
accettazione, problemi aperti, provenienza delle immagini e rollback ancora validi.
|
||||
5. **Riorganizzazione eventuale:** `docs/` per il pubblico, `developer-docs/` per
|
||||
architettura/contratti/ADR/testing, `project-notes/` per lavoro in corso. È un secondo
|
||||
intervento: aggiornare insieme tutti i link in README, AGENTS, CONTEXT, script e codice.
|
||||
|
||||
Per ogni ritiro usare un commit dedicato con motivazione e documento sostitutivo.
|
||||
Non creare una cartella `archive/` piena di copie obsolete: la cronologia Git è già
|
||||
l'archivio, salvo una necessità operativa o di conservazione esplicita.
|
||||
|
||||
## Inventario e destinazione proposta
|
||||
|
||||
L'inventario seguente distingue l'azione proposta dalla sola esclusione già applicata
|
||||
al sito. «Consolidare» e «ritirare» non indicano cancellazioni eseguite.
|
||||
|
||||
<!-- inventory:start -->
|
||||
| File (relativo a `docs/`) | Destinazione | Azione proposta |
|
||||
| --- | --- | --- |
|
||||
| `adr/0001-postgres-metadata-catalog.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0002-workspace-database-secret-references.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0003-installation-local-database-bindings.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0004-fastify-kysely-metadata-catalog.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0005-hard-delete-catalog-tables-during-synchronization.md` | Developer | Conservare ADR superato e catena dei successori; non eliminarlo. |
|
||||
| `adr/0006-separate-physical-and-logical-relationships.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0007-durable-authoritative-schema-synchronization.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0008-allow-manual-catalog-metadata-cleanup.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0009-use-one-sequential-description-generation-run.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0010-allow-bounded-real-source-samples-for-description-generation.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0011-gate-source-samples-with-a-sensitive-data-flag.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0012-use-the-catalog-as-the-logical-relationship-authority.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0013-use-one-installation-model-catalog-with-runtime-projections.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0014-assess-sensitive-columns-locally-from-source-content.md` | Developer | Conservare ADR superato e catena dei successori; non eliminarlo. |
|
||||
| `adr/0015-use-progressive-sampling-for-sensitive-columns.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0016-use-postgres-metadata-for-all-core-consumers.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0017-separate-reference-vectors-from-runtime-memory.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0018-use-postgres-for-memory-and-qdrant-for-retrieval.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0019-author-evidence-in-app-with-automatic-activation.md` | Developer | Conservare; allineare nome/stato alla decisione manuale effettiva. |
|
||||
| `adr/0020-unify-administration-pages-and-use-namespaced-routes.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0021-separate-shell-modes-and-replaceable-portal-adapter.md` | Developer | Conservare decisione architetturale. |
|
||||
| `adr/0022-separate-ui-locale-from-session-interaction-language.md` | Developer | Conservare decisione architetturale. |
|
||||
| `agents/domain.md` | Developer | Conservare regole di contribuzione/agenti, fuori dal sito. |
|
||||
| `agents/issue-tracker.md` | Developer | Conservare regole di contribuzione/agenti, fuori dal sito. |
|
||||
| `agents/triage-labels.md` | Developer | Conservare regole di contribuzione/agenti, fuori dal sito. |
|
||||
| `architecture/application-shell.md` | Developer | Conservare riferimento corrente; distinguere il prodotto dalla struttura del codice. |
|
||||
| `architecture/authentication.md` | Developer | Conservare riferimento corrente; distinguere il prodotto dalla struttura del codice. |
|
||||
| `architecture/components.md` | Developer | Conservare riferimento corrente; distinguere il prodotto dalla struttura del codice. |
|
||||
| `architecture/overview.md` | Developer | Conservare riferimento corrente; distinguere il prodotto dalla struttura del codice. |
|
||||
| `architecture/thothii-core-sequence.html` | Developer/build | Conservare sorgente/diagramma tecnico; non pubblicare nel manuale. |
|
||||
| `architecture/thothii-core-sequence.visual-check.1440x900.dark.png` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-core-sequence.visual-check.1440x900.light.png` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-core-sequence.visual-check.2048x1320.dark.png` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-core-sequence.visual-check.2048x1320.light.png` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-core-sequence.visual-check.html` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-core-sequence.visual-check.json` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-core.sequence.json` | Developer/build | Conservare sorgente/diagramma tecnico; non pubblicare nel manuale. |
|
||||
| `architecture/thothii-runtime.architecture.json` | Developer/build | Conservare sorgente/diagramma tecnico; non pubblicare nel manuale. |
|
||||
| `architecture/thothii-runtime.html` | Developer/build | Conservare sorgente/diagramma tecnico; non pubblicare nel manuale. |
|
||||
| `architecture/thothii-runtime.visual-check.1440x900.dark.png` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-runtime.visual-check.1440x900.light.png` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-runtime.visual-check.2048x1320.dark.png` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-runtime.visual-check.2048x1320.light.png` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-runtime.visual-check.html` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `architecture/thothii-runtime.visual-check.json` | Transitorio | Ritirare output QA rigenerabili dopo conferma che non siano baseline uniche. |
|
||||
| `contracts/archive-repair.md` | Developer | Conservare contratto e versioni semantiche; aggiornare insieme a codice/test. |
|
||||
| `contracts/catalog-schema-snapshot.md` | Developer | Conservare contratto e versioni semantiche; aggiornare insieme a codice/test. |
|
||||
| `contracts/curated-evidence-v4.md` | Developer | Conservare contratto e versioni semantiche; aggiornare insieme a codice/test. |
|
||||
| `contracts/portal-shell-adapter-v1.md` | Developer | Conservare contratto e versioni semantiche; aggiornare insieme a codice/test. |
|
||||
| `contracts/tht-dwh.md` | Developer | Conservare contratto e versioni semantiche; aggiornare insieme a codice/test. |
|
||||
| `contracts/workspace-evidence-v3.md` | Developer | Conservare contratto e versioni semantiche; aggiornare insieme a codice/test. |
|
||||
| `contracts/workspace-preprocessing-cli.md` | Developer | Conservare contratto e versioni semantiche; aggiornare insieme a codice/test. |
|
||||
| `disambiguazione-iniziale.md` | Developer | Conservare invarianti di gate/ledger; il percorso utente è in skills.md. |
|
||||
| `evidence.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `general/pi-configuration.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `gestione-memory.md` | Developer | Conservare contratto di Memory; istruzioni pubbliche in usage/memory.md. |
|
||||
| `guida-utente.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `index.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/authentication-local.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/authentication-oidc.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/authentication-upstream.md` | Developer/integratore | Conservare integrazione e confine di fiducia; guida pubblica separata. |
|
||||
| `install/authentik.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/dwh-auth-client-enrollment.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/dwh-auth-server.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/dwh-auth-tls.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/examples/thothii-installation.local.yaml` | Asset pubblico | Conservare asset o esempio operativo. |
|
||||
| `install/examples/thothii-installation.server.yaml` | Asset pubblico | Conservare asset o esempio operativo. |
|
||||
| `install/examples/workspace-bindings.env.example` | Asset pubblico | Conservare asset o esempio operativo. |
|
||||
| `install/first-start.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/standalone-manual-en.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `install/standalone-manual-it.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `installazione-docker-4-contesti.md` | Misto/transitorio | Estrarre dettagli server unici, poi ritirare la ricetta duplicata. |
|
||||
| `javascripts/layout-init.js` | Asset pubblico | Conservare asset o esempio operativo. |
|
||||
| `operations/database-management.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `operations/docker-refresh.md` | Operazioni interne | Conservare finché descrive il contesto locale attivo; poi consolidare il lifecycle. |
|
||||
| `operations/sensitivity-analysis.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `operations/server-codex-handoff.md` | Operazioni interne | Conservare runbook finché migrazione e rollback sono operativamente necessari. |
|
||||
| `operations/server-handoff-260906-preprocessing-complete.md` | Operazioni/transitorio | Confrontare con server-codex-handoff, assorbire passaggi unici, poi ritirare. |
|
||||
| `operations/server-upgrade-gitea-workspace-v2.md` | Operazioni interne | Conservare runbook finché migrazione e rollback sono operativamente necessari. |
|
||||
| `operations/shell-and-localization.md` | Developer/integratore | Conservare integrazione e confine di fiducia; guida pubblica separata. |
|
||||
| `operations/workspaces.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `plans/2026-08-26-metadata-catalog-from-thothai.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-08-28-ai-catalog-description-generation-spec.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-08-28-ai-catalog-description-generation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-02-installation-model-catalog.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-08-evidence-management.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-08-memory-evidence-administration.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-08-memory-evidence-simplification-review.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-08-memory-m1-spec.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-08-memory-m1-validation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-08-memory-management.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-08-security-hardening-prd.md` | Progetto attivo | Conservare PRD aperto; risolvere decisioni/issue prima del ritiro. |
|
||||
| `plans/2026-09-08-security-hardening-resume-prompt.md` | Transitorio | Ritirare dopo trasferimento di istruzioni e questioni aperte nel PRD/issue. |
|
||||
| `plans/2026-09-09-archive-repair-x1-validation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-09-evidence-e1-validation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-09-evidence-e2-validation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-09-evidence-e3-validation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-09-memory-m2-validation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-09-memory-m3-validation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-10-administration-pages-spec.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-13-full-shell-and-portal-integration.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-13-full-shell-spec.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/2026-09-14-manual-standalone-installation.md` | Progetto attivo | Conservare fino alla verifica su tre piattaforme; poi assorbire gate e ritirare. |
|
||||
| `plans/administration-pages/01-navigation.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/administration-pages/02-workspace-readiness.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/administration-pages/03-workbench-family.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `plans/administration-pages/04-embedded-acceptance.md` | Progetto/transitorio | Consolidare invarianti in contratti e gate in issue/test; poi ritirare piano o resoconto. |
|
||||
| `reports/2026-09-02-psd-sensitivity-shadow.md` | Developer/benchmark | Conservare risultati aggregati come evidenza versionata, non garanzia corrente. |
|
||||
| `reports/2026-09-02-sensitivity-ner-license-inventory.md` | Developer/release | Conservare provenienza licenze della release; rigenerare quando cambiano le dipendenze. |
|
||||
| `reports/2026-09-03-psd-progressive-sensitivity-shadow.md` | Developer/benchmark | Conservare risultati aggregati come evidenza versionata, non garanzia corrente. |
|
||||
| `reports/2026-09-12-admin-issues-28-31.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-12-context-shelf-a-implementation.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-12-ui-survey-and-graphic-revision-plan.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-12-ui-visual-review-delivery.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-12-unified-interaction-model.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-13-full-shell-implementation.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-13-header-layout-refinements.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-13-knowledge-reading.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-13-knowledge-typography.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-13-shell-simplification-review.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-13-visual-shell-integration.md` | Progetto/transitorio | Consolidare in record di release; ritirare solo dopo trasferimento gate/rollback utili. |
|
||||
| `reports/2026-09-14-session-dialogs-release.md` | Operazioni/release | Conservare finché accettazione, osservazione e rollback non sono chiusi. |
|
||||
| `reports/2026-09-14-session-layout-memory-fix.md` | Operazioni/release | Conservare finché accettazione, osservazione e rollback non sono chiusi. |
|
||||
| `requirements.lock` | Developer/build | Conservare dipendenze e lock; esclusi dal sito. |
|
||||
| `requirements.txt` | Developer/build | Conservare dipendenze e lock; esclusi dal sito. |
|
||||
| `research/2026-08-23-legacy-thothai-metadata-capabilities.md` | Storico/superato | Estrarre vincoli non assorbiti da ADR/contratti, poi ritirare. |
|
||||
| `research/2026-08-23-postgresql-catalog-deployment-constraints.md` | Storico/superato | Estrarre vincoli non assorbiti da ADR/contratti, poi ritirare. |
|
||||
| `research/2026-08-23-thothii-metadata-publication-qdrant-seams.md` | Storico/superato | Estrarre vincoli non assorbiti da ADR/contratti, poi ritirare. |
|
||||
| `research/2026-08-31-browser-erd-library-options.md` | Developer/ricerca | Verificare decisioni ancora aperte; assorbire conclusioni in issue/ADR, poi ritirare. |
|
||||
| `research/2026-08-31-relationship-management-thothai-to-thothii.md` | Developer/ricerca | Verificare decisioni ancora aperte; assorbire conclusioni in issue/ADR, poi ritirare. |
|
||||
| `research/2026-09-02-local-sensitive-column-classifier-libraries.md` | Developer/ricerca | Verificare decisioni ancora aperte; assorbire conclusioni in issue/ADR, poi ritirare. |
|
||||
| `research/2026-09-07-antigravity-gemini-flash-value.md` | Fuori prodotto | Proposta di ritiro dal working tree; Git o raccolta personale su scelta del proprietario. |
|
||||
| `research/2026-09-07-deepseek-harness-terminal.md` | Fuori prodotto | Proposta di ritiro dal working tree; Git o raccolta personale su scelta del proprietario. |
|
||||
| `research/2026-09-07-omp-codex-zcode.md` | Fuori prodotto | Proposta di ritiro dal working tree; Git o raccolta personale su scelta del proprietario. |
|
||||
| `research/2026-09-07-pi-config-vs-oh-my-pi.md` | Fuori prodotto | Proposta di ritiro dal working tree; Git o raccolta personale su scelta del proprietario. |
|
||||
| `research/2026-09-07-zai-coding-plan-cli-quota.md` | Fuori prodotto | Proposta di ritiro dal working tree; Git o raccolta personale su scelta del proprietario. |
|
||||
| `research/2026-09-07-zed-acp-omp-pi.md` | Fuori prodotto | Proposta di ritiro dal working tree; Git o raccolta personale su scelta del proprietario. |
|
||||
| `research/text-to-sql-products.md` | Fuori prodotto | Proposta di ritiro dal working tree; Git o raccolta personale su scelta del proprietario. |
|
||||
| `skills.md` | Pubblico | Conservare; istruzioni di prodotto/operatore. |
|
||||
| `stylesheets/extra.css` | Asset pubblico | Conservare asset o esempio operativo. |
|
||||
| `testing/2026-08-29-ai-catalog-description-generation-acceptance.md` | Developer/QA | Conservare criteri ripetibili e gate; separare risultati di singola release. |
|
||||
| `testing/2026-08-31-metadata-privacy-description-test-plan.md` | Developer/QA | Conservare scenari; ridurre duplicazioni e distinguere test proposti da eseguiti. |
|
||||
| `testing/authentication-manual-acceptance.md` | Developer/QA | Conservare criteri ripetibili e gate; separare risultati di singola release. |
|
||||
| `testing/evidence-lifecycle-test-plan.md` | Developer/QA | Conservare criteri ripetibili e gate; separare risultati di singola release. |
|
||||
<!-- inventory:end -->
|
||||
|
||||
## Verifica iniziale, prima dell'esecuzione dei ritiri
|
||||
|
||||
- Build MkDocs con `--strict` e dipendenze bloccate: superata.
|
||||
- Verifica confine pubblico: 20 pagine, nessun file interno generato o indicizzato.
|
||||
- Otto fixture positive/negative del confine pubblico: superate.
|
||||
- Suite corrente installazione/workspace: superata.
|
||||
- Due verificatori legacy: fallimenti preesistenti descritti sopra; non dichiarati verdi.
|
||||
- Nessuna certificazione di nuova installazione o nuovo collaudo applicativo.
|
||||
|
||||
La pubblicazione remota va verificata separatamente dalla build locale: il ramo sorgente
|
||||
`main`, il ramo generato `pages` e il sito servito non sono la stessa prova.
|
||||
|
||||
### Primo esito remoto del 15 settembre 2026 — diagnosi storica
|
||||
|
||||
Il commit `043ffdfa` è stato pubblicato su `main`. La
|
||||
[pipeline 122](https://git.tylconsulting.it/mptyl/ThothII/actions/runs/122) è terminata
|
||||
con successo e il ramo `pages` contiene 20 pagine pubbliche, senza pagine interne
|
||||
nell'indice di ricerca verificato anonimamente.
|
||||
|
||||
L'URL `https://git.tylconsulting.it/thothii-docs/` serve però ancora la home precedente,
|
||||
con `Last-Modified: Wed, 26 Aug 2026 09:00:07 GMT`; il suo indice di ricerca include
|
||||
ancora architettura e contratti. La richiesta senza cache restituisce lo stesso risultato.
|
||||
Nel repository la pipeline aggiorna soltanto il ramo `pages`: non è documentato il
|
||||
collegamento alla directory effettivamente servita dal web server.
|
||||
|
||||
Il tentativo SSH in sola lettura con la configurazione locale non è proseguito:
|
||||
manca una host key ED25519 conosciuta per `git.tylconsulting.it`. Non è stata disabilitata
|
||||
la verifica dell'identità del server. Servono host/alias amministrativo verificato e
|
||||
percorso o meccanismo di pubblicazione prima di intervenire sul sito effettivo.
|
||||
Al momento di quella verifica la copia servita restava da aggiornare. L'accesso è
|
||||
stato poi risolto usando l'alias SSH già configurato e fidato `contabo`; nessuna
|
||||
host key è stata aggirata.
|
||||
|
||||
## Verifica della bonifica eseguita
|
||||
|
||||
- Build MkDocs strict e confine pubblico: superati, 20 pagine.
|
||||
- Otto fixture del confine pubblico: superate.
|
||||
- Contratti auth/DWH correnti e relative fixture di mutazione: superati.
|
||||
- Suite installazione/workspace, Compose canonico e contratto comandi deployment: superate.
|
||||
- Link Markdown locali di README, PROJECT_STATE e tutti i documenti: nessun target mancante.
|
||||
- `git diff --check`: superato.
|
||||
- `test-no-deployment-coupling.sh`: resta rosso su rilievi preesistenti relativi
|
||||
a contenuti locali PSD e route Omics. Eseguita anche la versione dello script
|
||||
precedente alla bonifica: stesso esito e identico insieme di rilievi, nessuno nuovo.
|
||||
Non è un collaudo del sito e non è stato indebolito per nascondere i risultati.
|
||||
- Nessuna nuova certificazione applicativa, modifica del runtime o chiusura di
|
||||
collaudi reali. I gate elencati nello snapshot restano espliciti.
|
||||
|
||||
## Pubblicazione effettiva completata — 15 settembre 2026
|
||||
|
||||
- Sorgente: `4ff91e8d6e771545bc3d8e7a0ac0b027ef66ba14`, pubblicata su `main`.
|
||||
- [Pipeline 124](https://git.tylconsulting.it/mptyl/ThothII/actions/runs/124):
|
||||
completata con successo, inclusi i nuovi controlli auth/DWH e pubblicazione `pages`.
|
||||
- Release servita: `/srv/thothii-docs/releases/20260915T123738Z-4ff91e8d`.
|
||||
Il symlink `current` punta a questa release; ricreato soltanto `thothii-docs`.
|
||||
- Configurazione nginx copiata identica; container healthy. Confronto degli ID
|
||||
dei container prima/dopo: nessun altro container ricreato o fermato.
|
||||
- Verifica anonima HTTP: home, ricerca e guide manuali IT/EN rispondono 200.
|
||||
SHA-256 di home e indice remoto identici alla build locale; ricerca: 20 pagine,
|
||||
nessuna interna.
|
||||
- Campioni interni `architecture/overview/`, `plans/2026-09-08-memory-management/`
|
||||
e `operations/compose-reference/`: HTTP 404.
|
||||
- Release precedente `releases/20260826T090022Z-e910c7d` conservata per rollback;
|
||||
nessuna vecchia release cancellata. Pubblicazioni future richiedono il passaggio
|
||||
esplicito del runbook, non il solo push di `main`.
|
||||
|
||||
Il precedente blocco sulla copia statica obsoleta è quindi risolto.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Compose reference for maintainers
|
||||
|
||||
This is an internal topology reference, not a second fresh-installation recipe. Operators
|
||||
start with the [Italian](../install/standalone-manual-it.md) or
|
||||
[English](../install/standalone-manual-en.md) manual. It replaces the duplicated four-context
|
||||
Docker guide without changing the runtime.
|
||||
|
||||
The base topology contains frontend, core, catalog-db, qdrant, embedding, embedding-model-init,
|
||||
catalog-migrate and profile-gated workspace-maintenance. Pi runs in core; DWH and generative
|
||||
model endpoints remain installation settings. Reference preprocessing and Memory have distinct
|
||||
lifecycles and collections. See [preprocessing](../contracts/workspace-preprocessing-cli.md).
|
||||
|
||||
## Configuration and migration boundaries
|
||||
|
||||
- Use one physical absolute installation descriptor path, its generated operator environment,
|
||||
Compose project name, base/profile overlays, transport overlays and generated model overlay.
|
||||
Mixing a generic `deploy/env/local.env` invocation with a native `tht` installation creates
|
||||
a different stack; it is not an equivalent lifecycle command.
|
||||
- `THT_INSTALLATION_CONFIG_SOURCE` identifies the protected host descriptor. The read-only
|
||||
backend runtime mount is `/run/thothii-installation/thothii-installation.yaml`, exposed through
|
||||
`THT_INSTALLATION_CONFIG_FILE`; the runtime path is not a host source path.
|
||||
- Catalog runtime/migrator passwords and provider credentials are protected files. A provider's
|
||||
`authentication.apiKeyEnv` names an allowed bundle entry; it is not a raw key. Private CAs
|
||||
are separately mounted PEM files, not bundle values. See the repository's
|
||||
`deploy/secrets/README.md` and the [model catalog guide](../general/pi-configuration.md).
|
||||
- Generate projections after descriptor edits. Do not edit generated model/auth/frontend files.
|
||||
Apply the installation's normal restart process when authored configuration changes.
|
||||
- Explicitly start catalog-db and run catalog-migrate before application rollout on a fresh
|
||||
database or after an approved schema update. That service runs Catalog and Memory migrations;
|
||||
neither normal backend startup nor `tht start` implicitly performs them.
|
||||
- Server deployments retain their reviewed session/auth/network/storage overlays. A writable
|
||||
server Pi-state parent must be initialized with the regular targets expected by the read-only
|
||||
nested mounts; use `scripts/prepare-server-pi-state.sh` with the installation's verified UID/GID.
|
||||
|
||||
## Deployment-specific authority
|
||||
|
||||
For the prepared generic server environment, the base/profile/session override
|
||||
combination is `-f compose.yaml -f deploy/compose.server.yaml
|
||||
-f deploy/compose.session-server.yaml.example`, with `--env-file` supplied before
|
||||
the overrides. Add the reviewed transport/generated overlays for that installation;
|
||||
this fragment alone is not a complete startup command.
|
||||
|
||||
The current [server handoff](server-codex-handoff.md) and
|
||||
[legacy upgrade runbook](server-upgrade-gitea-workspace-v2.md) retain maintenance, backup and
|
||||
rollback gates. Embedded/upstream identity is not standalone OIDC. Local/standalone setup
|
||||
does not authorize replacing a running server stack, resetting volumes, or copying another
|
||||
machine's descriptor. `scripts/run-stack.sh` remains a low-level path for an explicitly
|
||||
prepared generic environment, not the public manual's default startup command.
|
||||
@@ -67,7 +67,7 @@ SSH uses a private key, optional key passphrase, mandatory `known_hosts`, and op
|
||||
TLS CA/server name. REST prefers `POST /rpc/schema_snapshot`; when it is absent, the catalog may
|
||||
use the same strict v1 snapshot through one read-only `POST /rpc/run_query`. An unavailable
|
||||
capability, malformed snapshot, or connector error applies no catalog changes. See the
|
||||
[schema snapshot contract](../contracts/catalog-schema-snapshot.md).
|
||||
[schema snapshot contract](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/catalog-schema-snapshot.md).
|
||||
|
||||
## Synchronize authoritative schema metadata
|
||||
|
||||
@@ -176,6 +176,6 @@ atomic operation. It skips empty generated descriptions, reports aggregate copie
|
||||
counts, and retains the generated text. Because this can replace reviewed descriptions, the
|
||||
interface requires explicit confirmation before applying it.
|
||||
|
||||
The decisions behind this surface are [ADRs 0001–0011](../adr/0001-postgres-metadata-catalog.md)
|
||||
The decisions behind this surface are [ADRs 0001–0011](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/adr/0001-postgres-metadata-catalog.md)
|
||||
and the detailed acceptance record is
|
||||
[AI catalog description generation acceptance](../testing/2026-08-29-ai-catalog-description-generation-acceptance.md).
|
||||
[AI catalog description generation acceptance](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/testing/2026-08-29-ai-catalog-description-generation-acceptance.md).
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# Publishing the public manual
|
||||
|
||||
This is an internal operator runbook. Publishing documentation must not recreate
|
||||
the ThothII application, Gitea, proxy, DWH or other documentation containers.
|
||||
|
||||
## Three separate states
|
||||
|
||||
1. `main` contains reviewed source and the public allowlist in `mkdocs.yml`.
|
||||
2. Gitea Actions builds and validates the generated `pages` branch. A successful
|
||||
Actions run alone does **not** update the live site.
|
||||
3. The live [manual](https://git.tylconsulting.it/thothii-docs/) is served by the
|
||||
dedicated `thothii-docs` nginx container on the host reached through the existing
|
||||
trusted SSH alias `contabo`. Its Compose project/service are `thothii-docs`/`docs`.
|
||||
|
||||
This procedure is manual. No timer, webhook, credential or automatic deployment
|
||||
has been added. Use the operator's existing SSH authorization and known host key;
|
||||
never disable host verification to make a publication work.
|
||||
|
||||
## Build and stage
|
||||
|
||||
From a clean ThothII `main` checkout already pushed to Gitea:
|
||||
|
||||
```sh
|
||||
git status --short
|
||||
git rev-parse HEAD
|
||||
./scripts/build-docs.sh
|
||||
bash scripts/auth-docs-smoke.sh
|
||||
bash scripts/verify-dwh-auth-docs.sh
|
||||
bash scripts/test-auth-docs-smoke.sh
|
||||
bash scripts/test-verify-dwh-auth-docs.sh
|
||||
```
|
||||
|
||||
The strict build also verifies the public boundary: exactly 20 navigation pages,
|
||||
five approved source assets, no internal pages/assets, and matching search entries.
|
||||
The locked Windmill theme requires a separate exact allowlist of 25 static assets;
|
||||
MkDocs applies `exclude_docs` to those files too. Never replace the list with broad
|
||||
directory exceptions. Sources under `docs/` may not shadow theme asset paths.
|
||||
The verifier follows stylesheet/script/image references and CSS font references
|
||||
from generated pages and fails when a local dependency is absent.
|
||||
|
||||
Choose a unique release identifier consisting of UTC timestamp and source SHA.
|
||||
Record the current symlink and container identity before proceeding:
|
||||
|
||||
```sh
|
||||
ssh -oBatchMode=yes -oStrictHostKeyChecking=yes contabo \
|
||||
'readlink /srv/thothii-docs/current; docker inspect --format "{{.Id}} {{.State.Health.Status}}" thothii-docs'
|
||||
```
|
||||
|
||||
On the server, create `/srv/thothii-docs/releases/RELEASE/site` only if RELEASE
|
||||
does not exist. Copy the current `nginx.conf` unchanged into the new release.
|
||||
Transfer the local built `site/` into that new empty directory with rsync over
|
||||
the same verified SSH connection. Do not use `--delete` against `current`, and do
|
||||
not edit routing, TLS, network or authentication configuration.
|
||||
|
||||
## Activate only this site
|
||||
|
||||
Replace RELEASE below with the validated identifier, not a user-supplied path.
|
||||
Keep the previously recorded release for rollback.
|
||||
|
||||
```sh
|
||||
cd /srv/thothii-docs
|
||||
test -f releases/RELEASE/site/index.html
|
||||
test -f releases/RELEASE/nginx.conf
|
||||
docker exec thothii-docs nginx -t
|
||||
ln -s releases/RELEASE current.next
|
||||
mv -Tf current.next current
|
||||
docker compose --project-name thothii-docs -f docker-compose.yml \
|
||||
up -d --no-deps --force-recreate docs
|
||||
```
|
||||
|
||||
Check that `current.next` does not already exist before creating it; stop if it
|
||||
does, because another publication or recovery may be in progress. Changing the
|
||||
symlink alone is insufficient: an existing Docker bind mount still resolves to
|
||||
the old release. The service recreation above remounts the new directory. It may
|
||||
briefly interrupt this manual only.
|
||||
|
||||
## Verify, record, or roll back
|
||||
|
||||
- Wait for `docker inspect` to report this container healthy; verify mounted
|
||||
paths and nginx configuration. Stop after a bounded timeout (for example 60 s).
|
||||
- Without login/cookies, require HTTP 200 for home, search and both
|
||||
`install/standalone-manual-it/` and `install/standalone-manual-en/`.
|
||||
- Compare live home and `search/search_index.json` checksums to the build. Search
|
||||
must contain only the 20 approved pages, never plans, reports or architecture.
|
||||
- Check the actual stylesheet and JavaScript URLs in both installation pages:
|
||||
HTTP 200, CSS served as `text/css`, JavaScript with a valid script content type,
|
||||
and fonts available. In a browser confirm the stylesheets load and the layout is
|
||||
styled. HTML 200 alone is not enough to accept a publication.
|
||||
- Require HTTP 404 for retired/internal paths, including `architecture/overview/`,
|
||||
`plans/2026-09-08-memory-management/`, and `operations/compose-reference/`.
|
||||
- Record source SHA, release ID, previous release and checks in the cleanup/release
|
||||
record. Do not call the publication complete solely because `pages` was pushed.
|
||||
|
||||
If health or public verification fails, point `current` back to the recorded
|
||||
previous release using a fresh temporary symlink and the same atomic rename, then
|
||||
recreate **only** service `docs` with the same Compose command. Verify health and
|
||||
old site availability. Do not delete either release during recovery. Historical
|
||||
releases are retained; pruning them requires a separate retention decision.
|
||||
@@ -118,12 +118,12 @@ other CPU workloads.
|
||||
Run the first evaluation in shadow mode: read the source with its existing read-only role, do not
|
||||
save proposed flags, and report only aggregate counts, rule IDs, coverage, and timings. Never copy
|
||||
matched values into test output. Use a separately approved, labeled Italian corpus to calculate
|
||||
precision and recall; raw PSD values must remain inside the authorized environment.
|
||||
precision and recall; source values must remain inside the authorized environment.
|
||||
|
||||
Inside the configured core runtime, the non-mutating command is:
|
||||
|
||||
```bash
|
||||
npm run sensitivity:shadow -- psd-clinical
|
||||
npm run sensitivity:shadow -- <workspace-id>
|
||||
```
|
||||
|
||||
It reads catalog metadata and source values but emits one aggregate JSON object with no database,
|
||||
@@ -139,12 +139,7 @@ Enabling NER by default requires all of these gates:
|
||||
If a gate fails, leave NER disabled. The deterministic policy remains available and produces the
|
||||
binary draft from its scan coverage; no content is sent to an internal or external LLM.
|
||||
|
||||
The first aggregate PSD shadow comparison is recorded in
|
||||
[`2026-09-02-psd-sensitivity-shadow.md`](../reports/2026-09-02-psd-sensitivity-shadow.md). On the
|
||||
local CPU runner, NER found additional entities but reduced total coverage under the superseded
|
||||
global deadline. The v2 benchmark removed that confounder: CPU NER added 18 sensitive proposals and
|
||||
increased the warm analysis time from 50.1 to 61.3 seconds. It remains opt-in until a labeled Italian
|
||||
evaluation establishes that the additional findings justify their false-positive rate and cost.
|
||||
The deterministic progressive PSD run is recorded in
|
||||
[`2026-09-03-psd-progressive-sensitivity-shadow.md`](../reports/2026-09-03-psd-progressive-sensitivity-shadow.md):
|
||||
both deterministic and CPU-NER profiles assessed all 2,275 columns with zero `unknown` decisions.
|
||||
Benchmarks from a particular installation are not a guarantee for another database or machine.
|
||||
NER remains opt-in until an approved evaluation establishes that additional findings justify
|
||||
their false-positive rate and operational cost. Keep benchmark and release records with the
|
||||
installation's technical evidence, separate from this operator procedure.
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
# Consegna a Codex sul server: ThothII e Omics Portal
|
||||
|
||||
Revisione: **14 settembre 2026**. Destinazione: Datamart Builder nel portale
|
||||
Omics esistente, non un nuovo sito standalone. Questo documento è la procedura
|
||||
di riferimento per questa consegna e sostituisce le precedenti istruzioni di
|
||||
trasporto/pubblicazione del codice Omics. La distribuzione parte dai sorgenti
|
||||
ThothII aggiornati su `main` e dal branch Omics disponibile su GitHub; nessuna
|
||||
replica del repository Omics ad altri servizi fa parte dell'intervento.
|
||||
|
||||
## Risultato da ottenere e limiti
|
||||
|
||||
- L'utente entra in Omics come oggi, sceglie **Datamart Builder** e trova ThothII
|
||||
già autenticato, senza un secondo login.
|
||||
- Omics mantiene header, navigazione sinistra, lingua, tema, fullscreen, nome
|
||||
utente e logout. ThothII occupa soltanto la zona centrale: **embedded/upstream**.
|
||||
- I dati e le identità esistenti, i workspace, i modelli approvati e le credenziali
|
||||
del server restano quelli del server. Il Mac rimane **full/local**, default EN.
|
||||
- L'intervento comprende il codice e la configurazione di entrambi gli
|
||||
applicativi, la rigenerazione delle proiezioni, le immagini e il collaudo.
|
||||
Un pull da solo non conclude l'installazione.
|
||||
|
||||
Codex può fare l'inventario, preparare modifiche e test isolati. Prima del fermo,
|
||||
delle migrazioni, della modifica del proxy o della ricreazione di servizi
|
||||
operativi, presenta i comandi risolti, backup e rollback e ottieni conferma della
|
||||
finestra di rilascio. Ferma il passaggio interessato se manca una credenziale,
|
||||
una decisione sulla migrazione o un prerequisito; non aggirare i controlli.
|
||||
Non modificare Authentik o il DWH per correggere la UI. Il DWH resta read-only.
|
||||
Non cancellare volumi, dati o modifiche locali e non stampare segreti nei report.
|
||||
|
||||
## 1. Identificare l'installazione realmente in uso
|
||||
|
||||
Leggi `AGENTS.md` e `PROJECT_STATE.md` nel checkout ThothII aggiornato. Individua
|
||||
il checkout operativo Omics, normalmente `/home/chirone/omics_portal`; conferma
|
||||
il percorso prima di usarlo. Registra per **entrambi** i progetti:
|
||||
|
||||
1. Percorso, branch, SHA, stato della working tree e revisioni delle immagini
|
||||
effettivamente in esecuzione. Il checkout appena aggiornato può non coincidere
|
||||
con quello da cui sono stati creati i container.
|
||||
2. Nomi progetto Compose, file Compose/override ordinati, env file, servizi,
|
||||
mount, porte e reti. Leggi le label Compose dei container per ricostruire
|
||||
l'avvio; filtra gli inspect, evitando dump di variabili segrete.
|
||||
3. Percorso assoluto del `thothii-installation.yaml`, suo schema/profile,
|
||||
`projectDirectory`, `envFile`, `overrides`, `authentication`, `shell` e modello
|
||||
dei dati persistenti. Usa solo percorsi Linux reali e file che esistono.
|
||||
4. Configurazione effettiva del core: modalità auth, `THOTH_PUBLIC_EXPOSURE`,
|
||||
`THT_SESSION_STORAGE`, binding workspace/database, percorsi degli archivi
|
||||
Evidence e Memory e delle credenziali Pi/provider.
|
||||
5. Origine HTTPS pubblica del portale, punto di terminazione TLS, percorso
|
||||
autenticato delle API, alias di rete e possibilità di accesso diretto al core.
|
||||
|
||||
**Completato quando:** esiste un inventario senza segreti e ogni comando di
|
||||
avvio è ricostruibile con percorsi/progetti effettivi. Non usare gli script
|
||||
temporanei `/private/tmp/…` o i percorsi `/Users/mp/…` del Mac. Gli override vanno
|
||||
conservati in un percorso operativo stabile sul server.
|
||||
|
||||
## 2. Verificare le revisioni dei due applicativi
|
||||
|
||||
### ThothII
|
||||
|
||||
Il checkout aggiornato deve essere su `main` e includere almeno
|
||||
`bdcd8fcd28f3011471d77224db9c3f5baf227995` e questo documento. Registra anche lo
|
||||
SHA effettivo di `main`, che include il commit di consegna e il merge successivi:
|
||||
|
||||
```bash
|
||||
git status --short --branch
|
||||
git rev-parse HEAD
|
||||
git merge-base --is-ancestor bdcd8fcd28f3011471d77224db9c3f5baf227995 HEAD
|
||||
```
|
||||
|
||||
Se il controllo fallisce, completa l'acquisizione della revisione approvata
|
||||
prima di toccare l'installazione. Non ricostruire a mano le singole modifiche UI:
|
||||
questa revisione contiene shell, autenticazione, i18n, workflow bilingue,
|
||||
amministrazione, typography e navigazione aggiornate.
|
||||
|
||||
### Omics Portal
|
||||
|
||||
Il pull di ThothII **non aggiorna Omics**. Consegna Omics verificata su GitHub:
|
||||
|
||||
- Repository: `https://github.com/Dallavilla-Tiziano/omics_portal.git`.
|
||||
- Branch: `codex/thothii-embedded-shell`.
|
||||
- SHA della consegna: `fca10901a73666ca257d8f4cc4b77066295c400a`.
|
||||
- Commit funzionale della shell: `95154e179144e2453b37ef2a63a65d6f377e4cf8`.
|
||||
|
||||
Nel checkout Omics confermato, acquisisci senza fare un pull/merge implicito:
|
||||
|
||||
```bash
|
||||
cd /home/chirone/omics_portal
|
||||
git status --short --branch
|
||||
git rev-parse HEAD
|
||||
git fetch --no-tags https://github.com/Dallavilla-Tiziano/omics_portal.git \
|
||||
refs/heads/codex/thothii-embedded-shell:refs/remotes/thothii-delivery/omics-shell
|
||||
git rev-parse refs/remotes/thothii-delivery/omics-shell
|
||||
git merge-base --is-ancestor 95154e179144e2453b37ef2a63a65d6f377e4cf8 \
|
||||
refs/remotes/thothii-delivery/omics-shell
|
||||
git diff --stat HEAD...refs/remotes/thothii-delivery/omics-shell
|
||||
```
|
||||
|
||||
Confronta lo SHA acquisito con quello sopra. In caso di consegna diversa chiedi
|
||||
quale revisione usare. Confronta inoltre le modifiche con i progressi del server:
|
||||
non sostituire l'intero portale con un checkout più vecchio. Se la consegna è già
|
||||
integrata verifica i file, senza ripetere il merge; altrimenti prepara la sua
|
||||
integrazione in un branch/worktree di revisione dal codice operativo. Risolvi
|
||||
eventuali conflitti preservando i cambiamenti del server, testa, quindi applica
|
||||
la revisione concordata nel rilascio. Non fare reset o force push.
|
||||
|
||||
I dettagli tecnici locali in `docs/thothii-integration.md` di Omics sono utili,
|
||||
ma il percorso operativo di questa consegna è quello di **questo documento**.
|
||||
La pubblicazione del codice Omics su altri remote non è un prerequisito.
|
||||
|
||||
**Completato quando:** una revisione integrata Omics conserva le funzionalità del
|
||||
server e soddisfa tutti i controlli dei file nella sezione 4.
|
||||
|
||||
## 3. Adeguare ThothII senza importare la configurazione del Mac
|
||||
|
||||
### CLI, descrittore e proiezioni
|
||||
|
||||
Aggiorna il **CLI nativo host** dal checkout ThothII approvato, conservando il
|
||||
vecchio binario per rollback. Non confonderlo con il CLI Python interno al core:
|
||||
|
||||
```bash
|
||||
./scripts/install-tht.sh
|
||||
command -v tht
|
||||
tht --help
|
||||
```
|
||||
|
||||
Il comando installa normalmente in `/usr/local/bin` e verifica la risoluzione
|
||||
su PATH. Se il server usa un'altra directory, mantieni quella usando
|
||||
`THT_INSTALL_DIRECTORY` con un percorso assoluto. Conserva proprietario e
|
||||
permessi protetti del descrittore (`0600` o `0400`). Nel descrittore esistente
|
||||
schema v2 modifica la sezione seguente, preservando gli altri valori:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: embedded
|
||||
defaultLocale: en
|
||||
adapter: omics-portal
|
||||
```
|
||||
|
||||
`en` è il fallback UI, non forza l'inglese sul portale: in embedded prevale la
|
||||
lingua renderizzata da Django. Mantieni il `profile` server approvato e i percorsi,
|
||||
la project/installation identity, lo storage e gli override del server. Se il
|
||||
descrittore manca o è legacy, prepara una migrazione separata dopo l'inventario;
|
||||
non rilanciare il setup locale e non copiare il descrittore Mac.
|
||||
|
||||
Usa una variabile di lavoro dedicata, valorizzata con il percorso **confermato**:
|
||||
|
||||
```bash
|
||||
THTII_INSTALLATION=/percorso/reale/thothii-installation.yaml
|
||||
tht --installation "$THTII_INSTALLATION" installation generate
|
||||
```
|
||||
|
||||
La generazione non avvia i servizi. Controlla `generated/frontend/config.js` e
|
||||
il suo mount read-only nel Compose generato; prima dell'override Omics deve
|
||||
contenere `backendBaseUrl: "/api"` e la shell embedded completa. Conserva anche
|
||||
le proiezioni generate di modelli/settings/Pi. Non mantenere copie manuali dei
|
||||
file generati: `thothii-installation.yaml` resta la sorgente authored.
|
||||
|
||||
### Autenticazione già fornita dal portale
|
||||
|
||||
Nell'override Compose persistente dell'installazione deve esserci:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
core:
|
||||
environment:
|
||||
AUTH_MODE: upstream
|
||||
```
|
||||
|
||||
Aggiungi il percorso dell'override all'elenco `overrides` del descrittore se non
|
||||
è già caricato. Controlla il Compose risolto: scrivere `AUTH_MODE` nel solo file
|
||||
env non garantisce che la variabile arrivi al container.
|
||||
|
||||
- `authentication.configDirectory` e `THT_AUTH_CONFIG_ROOT` devono indicare la
|
||||
directory protetta prevista, **senza un `auth.yaml` local/OIDC letto dal core**.
|
||||
Non cancellare un file esistente: se trovato, fermati e prepara il cambio auth
|
||||
con backup e una directory dedicata. `AUTH_MODE` insieme al file è rifiutato.
|
||||
- Per Omics non usare `authentication.runtimeProjection` né
|
||||
`THT_AUTH_RUNTIME_PROJECTION_ROOT`: appartengono all'accesso local/OIDC diretto.
|
||||
- Non creare utenti/password ThothII, nuovi client OIDC o callback per questo
|
||||
embedding. Non esiste `tht auth configure --mode upstream`.
|
||||
- Preserva la coppia stabile `(issuer, subject)` degli utenti (`portal`, ID
|
||||
Django); cambiarla può rendere invisibili le sessioni dei proprietari esistenti.
|
||||
|
||||
### Dati, storage e prerequisiti non grafici
|
||||
|
||||
La release corrente usa catalogo metadati interno PostgreSQL, workspace schema
|
||||
v4, Installation Model Catalog v2, Qdrant e Ollama per embedding; Pi gira nel
|
||||
core. Mantieni i provider e i binding reali del server, incluse credenziali e CA.
|
||||
I default del Mac non sono una richiesta di cambiare modello o database.
|
||||
|
||||
Il catalogo metadati e l'eventuale database delle sessioni sono **due funzioni
|
||||
distinte**. Con `THOTH_PUBLIC_EXPOSURE=true`, il core rifiuta
|
||||
`THT_SESSION_STORAGE=local`: verifica che il percorso PostgreSQL delle sessioni
|
||||
sia già configurato e validato. Se manca, presenta il piano di provisioning e
|
||||
migrazione; non disabilitare il controllo public-exposure per ottenere l'avvio.
|
||||
L'overlay session-server è opt-in e non migra automaticamente i vecchi archivi.
|
||||
|
||||
Se la versione operativa precede questi contratti, risolvi prima la migrazione
|
||||
dei dati con backup verificati. Le migrazioni del catalogo si eseguono tramite
|
||||
il job esplicito `catalog-migrate`; quelle delle sessioni, quando necessarie e
|
||||
approvate, tramite `session-migrate`. Nessuna riguarda il DWH o è sostituita da
|
||||
una sincronizzazione di schema dall'interfaccia.
|
||||
|
||||
**Completato quando:** il descrittore genera correttamente; la configurazione
|
||||
risolta contiene shell embedded, upstream senza doppia auth, storage compatibile,
|
||||
mount e reti corretti; ogni differenza infrastrutturale ha un piano approvato.
|
||||
|
||||
## 4. Verificare e integrare i file Omics
|
||||
|
||||
| File nel repository Omics | Risultato obbligatorio |
|
||||
| --- | --- |
|
||||
| `templates/kokoro/datamart_builder.html` | Mount `#root` nello stesso documento Django, senza iframe; altezza contenuta sotto la topbar e layout centrale responsive. Carica config, override limitato e asset in quest'ordine. |
|
||||
| `templates/base.html` | `{% get_current_language as CURRENT_LANGUAGE %}` e `<html lang="{{ CURRENT_LANGUAGE }}">`, preservando i block del template. |
|
||||
| `templates/partials/topbar.html` | `select.omics-language-select[data-lang]` con lingua Django, form `set_language` POST/CSRF/next; pulsante fullscreen con label ingresso/uscita e stato accessibile. Mantieni nome/logout Omics. |
|
||||
| `static/js/app.js` | Fullscreen reale del documento con `requestFullscreen`/`exitFullscreen`; ascolta gli eventi del browser, inclusa uscita con Esc, aggiorna icona/stato/label e gestisce rifiuti senza simulare successo. |
|
||||
| `locale/it/LC_MESSAGES/django.po` | Traduzioni dei nuovi controlli fullscreen; compilazione del catalogo distribuito. |
|
||||
| `kokoro/datamart_catalog_views.py` e routing | La pagina richiede `datamart_builder.access`; l'endpoint `/datamart-builder/api-auth` verifica la sessione Django e restituisce identità verificata o 403. Conserva questa parte già esistente. |
|
||||
| `nginx/nginx.conf` | API protette verso il core, asset/config verso il frontend, origine e SSE coerenti. Conserva anche le altre route del portale. |
|
||||
| `kokoro/templatetags/vite.py` | Manifest da `http://thothii-frontend:8080/.vite/manifest.json`, asset dal manifest, cache di 30 secondi. |
|
||||
| `kokoro/test_thothii_shell.py`, `test_support/thothii/` | Test isolati della pagina e dei controlli, da eseguire prima del rilascio. |
|
||||
|
||||
Il template deve fare questo **prima** di `{% vite_assets %}`:
|
||||
|
||||
```html
|
||||
<script src="/datamart-builder/config.js"></script>
|
||||
<script>
|
||||
window.__THOTHII_CONFIG__ = Object.assign({}, window.__THOTHII_CONFIG__ || {}, {
|
||||
backendBaseUrl: '/datamart-builder/api'
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
L'override non deve sostituire l'intero oggetto perdendo `shell`. Nel browser il
|
||||
risultato deve avere `/datamart-builder/api` e `shell.mode === "embedded"`.
|
||||
`config.js` deve avere `Cache-Control: no-store`; gli asset con hash possono
|
||||
avere cache lunga. Non codificare a mano i nomi dei bundle Vite.
|
||||
|
||||
Il tema deve essere espresso come `data-bs-theme="light"` o `"dark"` su `html`.
|
||||
`OmicsPortalAdapter` in ThothII osserva quel dato, legge il `data-lang` renderizzato
|
||||
dal selettore e lo stato fullscreen. Non richiede nuovi eventi, handshake o
|
||||
token JavaScript. Se il contesto manca va corretto il template, non aggirato
|
||||
l'errore con un header full. I dettagli del portale restano nel solo adapter.
|
||||
|
||||
### Proxy e identità: controllo obbligatorio
|
||||
|
||||
Il flusso è browser → Nginx Omics → controllo Django → core ThothII:
|
||||
|
||||
1. `/datamart-builder/api/…` usa `auth_request /_thothii_auth`.
|
||||
2. La location interna interroga `/datamart-builder/api-auth` usando il cookie
|
||||
Omics. Django risponde 200 se autorizzato, 403 senza sessione/capability.
|
||||
3. Nginx usa solo gli header **della risposta Django** e sovrascrive gli eventuali
|
||||
valori client: `X-Thoth-Principal-Issuer: portal`,
|
||||
`X-Thoth-Principal-Subject: <user.pk>`, `X-Thoth-Principal-Display-Name` e
|
||||
`X-Thoth-Is-Admin: true|false` secondo `is_authentik_admin(user)`.
|
||||
4. Il proxy rimuove `Cookie`, `Authorization` e `X-Authenticated-User` prima del
|
||||
core, toglie il prefisso API e inoltra a `thothii-core:8787`. Non usare qui
|
||||
gli header `X-Thoth-Trusted-*` dell'esempio generico a due hop.
|
||||
5. Config/asset e manifest arrivano da `thothii-frontend:8080`. Omics web deve
|
||||
raggiungere il manifest; Nginx deve raggiungere entrambi gli alias privati.
|
||||
|
||||
Integra i servizi nella rete effettiva del portale, con alias non ambigui;
|
||||
non collegare due core candidati con lo stesso alias. Il core upstream deve
|
||||
essere irraggiungibile direttamente da browser/client non fidati, inclusi
|
||||
percorsi alternativi attraverso un frontend o proxy non protetto.
|
||||
|
||||
Conserva buffering/cache disattivati e timeout lunghi per SSE anche nel proxy
|
||||
a monte. Verifica l'Origin delle scritture: il codice Omics contiene la mappa
|
||||
esatta da `https://aritmolab.policlinicosandonato.it` a
|
||||
`http://aritmolab.policlinicosandonato.it` per la terminazione TLS esterna.
|
||||
Conferma che la topologia sia ancora quella. Se differisce, correggi Host,
|
||||
protocollo e mappa esatta con un test di rifiuto cross-origin; non cancellare
|
||||
Origin, non usare wildcard né rendere fidati gli header forniti dal browser.
|
||||
|
||||
Riferimento per errori 401/403 e contratto completo:
|
||||
[autenticazione upstream](../install/authentication-upstream.md).
|
||||
|
||||
## 5. Test, backup e rilascio coordinato
|
||||
|
||||
Dal checkout Omics integrato, senza database operativo o volumi collegati:
|
||||
|
||||
```bash
|
||||
docker build -f test_support/thothii/Dockerfile -t omics-portal:thothii-shell-tests .
|
||||
docker run --rm --network none omics-portal:thothii-shell-tests
|
||||
```
|
||||
|
||||
In ThothII verifica la build di frontend/core, i test auth e shell e la
|
||||
generazione del descrittore con il CLI aggiornato. I test locali alla consegna
|
||||
includono 768 test frontend, 20 scenari browser e build documentale strict;
|
||||
non certificano il portale/IdP né i dati del server.
|
||||
|
||||
Prima del rilascio prepara un piano con i **comandi esatti risolti**. Per
|
||||
installazioni già governate dal CLI usa `tht --installation …`; per launcher
|
||||
server personalizzati conserva progetto, ordine di tutti gli override e bind.
|
||||
Non alternare i due lifecycle se cambiano la project identity o i volumi.
|
||||
|
||||
Ordine da applicare nella finestra confermata:
|
||||
|
||||
1. Metti al sicuro revisioni, binario host, descrittore/env/override, immagini e
|
||||
backup consistenti di catalogo, sessioni, registry/Evidence/Memory, settings,
|
||||
Pi e indici. Proteggi i backup che contengono segreti. Verifica il ripristino
|
||||
prima di una migrazione non reversibile e gestisci le sessioni in corso.
|
||||
2. Genera le proiezioni dell'installazione; costruisci **core e frontend** dai
|
||||
sorgenti approvati. Avvia i servizi di supporto necessari e, se richiesto dal
|
||||
salto di versione, esegui le migrazioni esplicite con exit 0 prima del core.
|
||||
Il normale `tht start --build` coordina il lifecycle, non è frontend-only.
|
||||
3. Ricrea i servizi applicativi ThothII con configurazione embedded/upstream e
|
||||
conserva il progetto/dati approvati. Controlla health e diagnostica:
|
||||
|
||||
```bash
|
||||
tht --installation "$THTII_INSTALLATION" status
|
||||
tht --installation "$THTII_INSTALLATION" doctor --json
|
||||
```
|
||||
|
||||
4. Distribuisci la revisione Omics integrata tramite il suo normale rilascio,
|
||||
includendo `web`, statici/cataloghi e configurazione `nginx`. Il suo entrypoint
|
||||
esegue `migrate`, `compilemessages` e `collectstatic`: le modifiche della shell
|
||||
non aggiungono migrazioni Django, ma controlla quelle pendenti del server prima
|
||||
del riavvio. Verifica anche il catalogo Superset richiesto dalla build Omics.
|
||||
5. Esegui `nginx -t` nel servizio candidato e applica il reload/riavvio secondo
|
||||
la topologia registrata. Dopo la ricreazione dei container verifica che il
|
||||
proxy risolva gli alias ai nuovi indirizzi, non a IP Docker precedenti.
|
||||
6. Attendi almeno 30 secondi per la cache manifest Django o invalidala con il
|
||||
meccanismo del portale. Verifica asset/config e svolgi il collaudo seguente.
|
||||
|
||||
Se uno step fallisce non marcare l'installazione conclusa. Un core healthy non
|
||||
prova che auth, UI embedded o scritture attraverso il proxy funzionino.
|
||||
|
||||
## 6. Accettazione prima di dichiarare completato
|
||||
|
||||
Usa account di prova autorizzati e dati non operativi per i test che scrivono.
|
||||
Le verifiche che richiedono login interattivo possono essere svolte dall'operatore:
|
||||
riporta esplicitamente quelle ancora da fare, senza spuntarle per deduzione.
|
||||
|
||||
- **Accesso:** login Omics, apertura da menu, nessun login/header ThothII. `/me`
|
||||
su `/datamart-builder/api/me` restituisce identità e permessi corretti;
|
||||
`session`/`csrfToken` sono null in upstream.
|
||||
- **Dinieghi:** senza sessione o capability il proxy nega; header principal
|
||||
falsificati non danno accesso. Utente normale senza controlli admin; admin
|
||||
autorizzato con controlli coerenti. Nessuna route diretta aggira il proxy.
|
||||
- **Lingua e continuità:** IT/EN prima e dopo l'apertura, cambio attraverso Omics,
|
||||
ripristino della selezione dopo reload senza generazione automatica. Nuove
|
||||
sessioni ricevono la lingua UI; sessioni riprese mantengono
|
||||
`interaction_language`. Per quelle legacy la prima ripresa fissa la lingua
|
||||
del workspace in modo idempotente. SQL e contenuti authored non sono tradotti.
|
||||
- **Tema/fullscreen:** light/dark cambia anche ThothII, incluse finestre e menu;
|
||||
fullscreen nasconde il bordo browser, sostituisce l'icona e torna normale con
|
||||
Esc. Header/sidebar Omics mantengono il proprio aspetto.
|
||||
- **Logout:** il logout è soltanto quello Omics. Ritorno alla pagina e
|
||||
riconnessione ricontrollano l'accesso; non promettere revoca istantanea di uno
|
||||
stream già aperto in un'altra scheda.
|
||||
- **Workflow:** una sessione di prova autorizzata può essere creata, ricevere
|
||||
eventi SSE e domande/scelte nella lingua corretta, salvare e riprendere senza
|
||||
perdere proprietà. Le scritture same-origin funzionano, quelle cross-origin
|
||||
non autorizzate vengono negate.
|
||||
- **Amministrazione/UI:** Database, Memory ed Evidence leggibili, font/layout
|
||||
aggiornati e nessuna propagazione del reset CSS alla topbar Omics. Le memory
|
||||
FAKE sono solo esempi UI isolati, non da importare nel catalogo o nel recall.
|
||||
Puntino readiness Workspace, unico bottone Sessione, tab con bordi uniformi;
|
||||
accordion inizialmente chiuso, un solo pannello aperto, selezione per lista,
|
||||
scroll interno e nessuna frase “Inizia con Sessione”.
|
||||
- **Operatività:** nessun errore di config/auth nei log, mount e permessi corretti,
|
||||
indici/cataloghi e dati precedenti disponibili, nessuna modifica al DWH/IdP.
|
||||
|
||||
Compila il report con SHA ThothII/Omics, immagini, percorsi configurazione,
|
||||
comandi eseguiti, risultati e prove manuali pendenti, senza cookie o token.
|
||||
La [matrice auth completa](../testing/authentication-manual-acceptance.md)
|
||||
approfondisce i casi di sicurezza.
|
||||
|
||||
## 7. Rollback
|
||||
|
||||
Ripristina la coppia compatibile di codice/immagini **Omics e ThothII**, il CLI,
|
||||
descrittore e proiezioni registrati, seguendo il lifecycle approvato. Riavvia il
|
||||
proxy se necessario per DNS/config e ricontrolla manifest, accesso e SSE.
|
||||
I dati restano preservati: nessun `down --volumes`, cancellazione di archivi o
|
||||
reset distruttivo. Se il rilascio ha migrato uno schema o scritto dati non
|
||||
compatibili con la versione precedente, usa il piano di ripristino dati approvato,
|
||||
non un semplice downgrade d'immagine. Il rollback termina solo dopo il collaudo
|
||||
della versione ripristinata.
|
||||
@@ -4,6 +4,22 @@ Questo runbook è il passaggio di consegne per il Codex che opererà sul server
|
||||
installazione precedente alla configurazione corrente di ThothII senza modificare Authentik o il
|
||||
DWH esterno e senza cancellare lo stack precedente durante il primo cutover.
|
||||
|
||||
## Scelta preliminare: server autonomo oppure Omics
|
||||
|
||||
I passaggi di questo runbook che configurano OIDC diretto, gruppi e
|
||||
`authentication.runtimeProjection` riguardano **ThothII autonomo**, da rendere
|
||||
con `shell.mode: full`. Non applicarli all'integrazione Datamart Builder: Omics
|
||||
usa **embedded/upstream** e mantiene il proprio accesso Authentik. Il core riceve
|
||||
l'identità verificata dal proxy senza un secondo login né un secondo auth.yaml.
|
||||
|
||||
Prima dell'inventario identificare quale percorso è approvato. Per Omics seguire
|
||||
[autenticazione upstream](../install/authentication-upstream.md) e
|
||||
[rilascio coordinato dei due repository](shell-and-localization.md#preparare-il-rilascio-coordinato);
|
||||
i gate di backup, isolamento, catalogo, storage e rollback di questo runbook
|
||||
rimangono validi, ma non copiare i passi auth del percorso autonomo. Il passaggio
|
||||
da issuer `portal` a un issuer OIDC differente non trasferisce automaticamente
|
||||
la proprietà delle sessioni.
|
||||
|
||||
La procedura si applica a `main` quando contiene almeno il commit
|
||||
`eba6148511675fc6a187aabb69a975adc5e3c542`. Deve essere presente anche questo file. Il commit
|
||||
minimo è un controllo di sicurezza, non un invito a fermarsi a quella revisione: installare sempre
|
||||
@@ -11,6 +27,9 @@ la `origin/main` approvata dall'operatore.
|
||||
|
||||
## Regole non negoziabili
|
||||
|
||||
- Per il rilascio Omics seguire la [consegna corrente a Codex sul server](server-codex-handoff.md).
|
||||
Acquisire il branch dedicato da GitHub, verificare SHA e integrarlo con i
|
||||
progressi del server; nessuna replica del repository è richiesta.
|
||||
- Eseguire prima l'intero inventario in sola lettura e consegnarlo all'operatore.
|
||||
- Non stampare mai password, token, chiavi private, cookie, file `.env` o contenuti dei Docker
|
||||
secret. Nei report sono ammessi solo percorsi, nomi delle variabili e valori non segreti.
|
||||
@@ -51,7 +70,9 @@ La topologia base attesa è:
|
||||
| `embedding-model-init` | scarica/verifica il modello | job one-shot, deve terminare con exit 0 |
|
||||
|
||||
`catalog-db` non è il DWH. Non pubblica porte sull'host e usa credenziali runtime e migrator
|
||||
separate. Ollama non controlla le password utente: l'autenticazione resta OIDC tramite Authentik.
|
||||
separate. Ollama non controlla le password utente: nel percorso autonomo vale
|
||||
OIDC tramite Authentik; nel percorso embedded Omics verifica l'accesso e il core
|
||||
usa upstream.
|
||||
|
||||
Il PostgreSQL per le **sessioni** è un'altra funzione ancora. L'overlay
|
||||
`deploy/compose.session-server.yaml.example` è esplicitamente opt-in: non abilitarlo durante questo
|
||||
@@ -701,6 +722,6 @@ la nuova installazione è ferma ma ispezionabile.
|
||||
- [OIDC generico](../install/authentication-oidc.md)
|
||||
- [Operazioni workspace](workspaces.md)
|
||||
- [Configurazione dei modelli Pi](../general/pi-configuration.md)
|
||||
- [Contesti Docker](../installazione-docker-4-contesti.md)
|
||||
- [Contesti Docker](compose-reference.md)
|
||||
- [Database Management](database-management.md)
|
||||
- [Analisi locale della sensibilità](sensitivity-analysis.md)
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
# Shell, autenticazione e lingue
|
||||
|
||||
Questa è la procedura operativa del rendering corrente. Leggerla insieme a
|
||||
[architettura full/embedded](../architecture/application-shell.md),
|
||||
[autenticazione upstream](../install/authentication-upstream.md) e
|
||||
[contratto PortalAdapter](../contracts/portal-shell-adapter-v1.md).
|
||||
La [specifica approvata](../plans/2026-09-13-full-shell-spec.md) documenta la
|
||||
progettazione, non sostituisce i vincoli verificati nel codice e riportati qui.
|
||||
|
||||
## Scegliere il contenitore
|
||||
|
||||
La modalità della shell è indipendente dal profilo di distribuzione e dal metodo
|
||||
di autenticazione. Un server può ospitare full; un ambiente locale può ospitare
|
||||
embedded per provare un'integrazione.
|
||||
|
||||
| Destinazione | Shell | Autorità di accesso | Login/logout visibile |
|
||||
| --- | --- | --- | --- |
|
||||
| Mac attuale | full, default en | `auth.yaml` local | ThothII |
|
||||
| Server autonomo | full | `auth.yaml` OIDC | ThothII, con redirect al provider |
|
||||
| Datamart Builder in Omics | embedded, adapter Omics | core `AUTH_MODE=upstream`, sessione Omics al proxy | Solo Omics |
|
||||
|
||||
Non confondere la lingua inglese iniziale del Mac con quella del workspace o
|
||||
delle sessioni già create. Non copiare sul server l'intero descrittore del Mac:
|
||||
contiene percorsi e scelte locali, oltre a full.
|
||||
|
||||
Per questo Mac, nel descrittore installato:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: full
|
||||
defaultLocale: en
|
||||
```
|
||||
|
||||
Per il server Omics:
|
||||
|
||||
```yaml
|
||||
shell:
|
||||
mode: embedded
|
||||
defaultLocale: en
|
||||
adapter: omics-portal
|
||||
```
|
||||
|
||||
L'assenza di `shell` conserva embedded con adapter Omics. Un nome adapter
|
||||
sconosciuto è un errore, non una richiesta di fallback a full. Full ignora
|
||||
l'adapter Omics riconosciuto e non lo istanzia. Un locale ben formato per cui non
|
||||
esiste ancora un catalogo usa l'inglese nell'interfaccia.
|
||||
|
||||
`defaultLocale` è il valore iniziale, non un vincolo che annulla ogni scelta
|
||||
dell'utente. Full ricorda lingua e tema nel browser; embedded segue soltanto
|
||||
Omics. Le preferenze non modificano il descrittore installato.
|
||||
|
||||
## Applicare una modifica all'installazione
|
||||
|
||||
Per una nuova installazione autonoma, selezionare esplicitamente full:
|
||||
|
||||
```bash
|
||||
tht setup --complete --profile local --shell-mode full --shell-default-locale en
|
||||
```
|
||||
|
||||
Il setup senza opzioni shell conserva per compatibilità il default embedded.
|
||||
Per un'installazione esistente non rilanciare setup per sovrascrivere il
|
||||
descrittore: registrare la configurazione attuale, modificarne la sezione shell
|
||||
e usare la generazione seguente. Le credenziali rimangono nei file protetti.
|
||||
|
||||
Aggiornare prima il binario nativo `tht`: le versioni precedenti rifiutano la
|
||||
sezione `shell`. Modificare poi il descrittore e generare le proiezioni:
|
||||
|
||||
```bash
|
||||
tht --installation /percorso/assoluto/thothii-installation.yaml installation generate
|
||||
```
|
||||
|
||||
Il comando non avvia né arresta servizi. Genera anche
|
||||
`generated/frontend/config.js`, che contiene configurazione pubblica, e il
|
||||
relativo mount Compose. Non modificare a mano i file generati. `tht start`
|
||||
rigenera le proiezioni nel normale percorso di avvio.
|
||||
|
||||
Applicare il normale processo di aggiornamento dei container dell'installazione.
|
||||
Se si usa un launcher Compose personalizzato, deve includere la proiezione
|
||||
Compose generata e ricreare il frontend quando cambia la configurazione. Il
|
||||
fingerprint della configurazione pubblica permette a Compose di rilevare il cambio.
|
||||
La stessa immagine frontend supporta entrambe le modalità.
|
||||
|
||||
Nel percorso standard del CLI, dopo avere approvato l'aggiornamento:
|
||||
|
||||
```bash
|
||||
tht --installation /percorso/assoluto/thothii-installation.yaml start
|
||||
tht --installation /percorso/assoluto/thothii-installation.yaml status
|
||||
tht --installation /percorso/assoluto/thothii-installation.yaml doctor --json
|
||||
```
|
||||
|
||||
Usare `start --build` per una revisione di codice che richiede nuove immagini,
|
||||
non per la sola modifica della shell. Questo è un lifecycle dell'installazione,
|
||||
non un comando garantito frontend-only. Un launcher personalizzato deve conservare
|
||||
tutti gli override di rete, autenticazione, workspace e modelli già approvati.
|
||||
Non usare `down --volumes`. Registrare gli identificatori delle immagini prima
|
||||
dell'aggiornamento e conservare il descrittore precedente per il rollback.
|
||||
|
||||
Controllare il `config.js` effettivamente servito, che non deve essere memorizzato
|
||||
in cache. In full la route API ordinaria è `/api`; Omics imposta nel template il
|
||||
prefisso same-origin `/datamart-builder/api`, mantenendo le altre impostazioni.
|
||||
|
||||
Il file pubblico standalone deve essere equivalente a:
|
||||
|
||||
```javascript
|
||||
window.__THOTHII_CONFIG__ = {
|
||||
backendBaseUrl: "/api",
|
||||
shell: { mode: "full", defaultLocale: "en" }
|
||||
};
|
||||
```
|
||||
|
||||
È un risultato da controllare, non un file da mantenere a mano. In Omics il
|
||||
template carica `/datamart-builder/config.js`, conserva l'oggetto con
|
||||
`Object.assign` cambiando solo `backendBaseUrl` in `/datamart-builder/api`, poi
|
||||
carica gli asset dal manifest. Il config senza cache deve precedere ogni modulo
|
||||
React; verificare nella rete del browser l'URL finale `/datamart-builder/api/me`.
|
||||
|
||||
## Accesso in parole semplici
|
||||
|
||||
In Omics l'utente effettua l'accesso al portale come oggi. Quando sceglie
|
||||
Datamart Builder, il server controlla che possa usarlo e comunica a ThothII chi è.
|
||||
ThothII apre l'applicazione per quella persona: non presenta un altro login e non
|
||||
crea una seconda sessione browser. Le password non vengono trasmesse a ThothII.
|
||||
Il nome e il comando Esci rimangono nell'header del portale.
|
||||
|
||||
Sul Mac full, ThothII presenta il proprio login locale. Dopo l'accesso mostra il
|
||||
nome nell'header; il menu del nome contiene il logout. Riutilizza gli utenti e
|
||||
la configurazione di accesso dell'installazione. Full supporta anche un'eventuale
|
||||
autenticazione OIDC configurata; il suo logout termina la sessione ThothII, non
|
||||
promette di disconnettere l'utente da tutti gli altri servizi OIDC.
|
||||
|
||||
Full/upstream non può terminare una sessione posseduta dal proxy e non mostra
|
||||
quel comando logout. Embedded non presenta mai il login ThothII, neppure per
|
||||
recuperare un errore di configurazione. Per un server autonomo con login/logout
|
||||
ThothII usare full/OIDC, non full/upstream.
|
||||
|
||||
I controlli server restano autorevoli. Un errore su una singola operazione non
|
||||
deve cancellare automaticamente l'accesso all'intera applicazione. Un rifiuto
|
||||
della verifica dell'utente chiude invece lo stato protetto. L'accesso viene
|
||||
ricontrollato anche al ritorno alla pagina e quando il collegamento eventi deve
|
||||
riconnettersi. Questo non equivale a una revoca istantanea di ogni connessione
|
||||
già aperta in altre schede.
|
||||
|
||||
## Contratto server Omics
|
||||
|
||||
Il percorso corrente usa il controllo Django della capability
|
||||
`datamart_builder.access`, la subrequest nginx `auth_request` e gli header
|
||||
normalizzati `X-Thoth-Principal-Issuer`, `X-Thoth-Principal-Subject`,
|
||||
`X-Thoth-Principal-Display-Name` e `X-Thoth-Is-Admin`. Il browser non può
|
||||
scegliere queste identità: il proxy ricava gli header dal controllo server e
|
||||
sostituisce quelli eventualmente forniti dal client.
|
||||
|
||||
Mantenere il backend configurato per l'autenticazione upstream e i suoi controlli
|
||||
di autorizzazione. Non esporre un percorso alternativo che permetta al browser
|
||||
di raggiungerlo aggirando quel controllo. Non introdurre token nel documento,
|
||||
negli eventi UI o nella configurazione pubblica.
|
||||
|
||||
La [guida upstream](../install/authentication-upstream.md) riporta i vincoli
|
||||
esatti: `AUTH_MODE=upstream` nel core, nessun `auth.yaml` o runtime projection
|
||||
contemporaneo, capability Django, quattro header obbligatori/facoltativi, percorso
|
||||
diretto Omics distinto dal proxy generico a due hop, origine e SSE. Non usare
|
||||
`tht auth configure --mode oidc` per «completare» l'accesso Omics già funzionante.
|
||||
|
||||
## Come funziona l'adapter
|
||||
|
||||
`OmicsPortalAdapter` è il solo modulo frontend che conosce il documento Omics.
|
||||
Legge il `data-lang` del selettore lingua, osserva `data-bs-theme` e ascolta lo
|
||||
stato fullscreen del documento. Fornisce snapshot `{ locale, theme, fullscreen }`
|
||||
al controller di shell. Non invia comandi al portale e non usa un handshake.
|
||||
|
||||
La pagina Omics deve continuare a esporre il selettore
|
||||
`select.omics-language-select` con la lingua renderizzata nel suo `data-lang`, e
|
||||
il tema light/dark nell'attributo di `html`. Il selettore lingua usa il normale
|
||||
form Django; non occorre convertirlo in una richiesta asincrona.
|
||||
|
||||
Per un altro portale, implementare la stessa sottoscrizione e selezionare il
|
||||
nuovo adapter nel punto di composizione. Le pagine, l'i18n e il workflow non
|
||||
devono acquisire riferimenti al nuovo portale. Sul lato server, il nuovo
|
||||
contenitore deve anche fornire un'identità verificata conforme al contratto
|
||||
upstream. Cambiare una classe JavaScript non sostituisce quel requisito.
|
||||
|
||||
## Lingue e sessioni
|
||||
|
||||
Ci sono tre scelte distinte:
|
||||
|
||||
| Scelta | Dove viene conservata | Cosa influenza |
|
||||
| --- | --- | --- |
|
||||
| Lingua UI | preferenza full o stato Omics | navigazione, amministrazione e messaggi generali |
|
||||
| Lingua di interazione | `interaction_language` nel manifest | domande, spiegazioni, scelte e controlli HITL |
|
||||
| Lingua workspace | configurazione del workspace | documenti, descrizioni e contenuti di dominio |
|
||||
|
||||
La creazione web acquisisce la lingua UI prima delle operazioni asincrone e la
|
||||
invia come `interactionLanguage` di ripiego. Il CLI riconosce localmente la lingua
|
||||
della domanda originale e la fissa nel manifest; usa il ripiego per testo troppo
|
||||
breve, ambiguo o composto soltanto da codice. Un cambio successivo non modifica
|
||||
quella richiesta. Il gate trasmette la lingua nei widget: anche i controlli HITL
|
||||
seguono la sessione, mentre la navigazione conserva la lingua UI.
|
||||
La ripresa legge il manifest e non usa il locale del browser come
|
||||
override. SQL, identificatori, valori e citazioni dei contenuti rimangono invariati.
|
||||
|
||||
Per sessioni precedenti senza `interaction_language`, la prima ripresa fissa la
|
||||
lingua della domanda in modo idempotente, usando la lingua del workspace come
|
||||
ripiego. Le sessioni che hanno già una lingua fissata la conservano.
|
||||
|
||||
Il cambio lingua di Omics ricarica la pagina. ThothII ricorda soltanto l'identificatore
|
||||
della sessione per utente e pagina, senza salvare una trascrizione nel browser.
|
||||
Il recupero riapre il pannello dei documenti; la ripresa operativa è esplicita e
|
||||
non avvia una generazione soltanto perché la pagina è stata ricaricata. Le bozze
|
||||
non inviate e le modifiche amministrative richiedono protezione dalla navigazione.
|
||||
|
||||
## Aggiungere e verificare traduzioni
|
||||
|
||||
I messaggi inglesi fungono da identificatori gettext-style e fallback. I
|
||||
cataloghi italiani sono divisi per area per agevolarne la manutenzione. Usare
|
||||
`useI18n()` nei componenti e interpolazioni nominate, evitando concatenazioni
|
||||
che rendano impossibile cambiare l'ordine delle parole. Non chiamare il traduttore
|
||||
su SQL, testi del modello o descrizioni del workspace.
|
||||
|
||||
Per una nuova lingua aggiungere il catalogo, registrarlo nel risolutore e renderlo
|
||||
disponibile nel selettore full. Il portale deve fornire il relativo locale. La
|
||||
lingua delle sessioni è già esplicita e non richiede una nuova struttura del manifest.
|
||||
Le traduzioni dei controlli della griglia provengono dal catalogo ufficiale della
|
||||
stessa versione di AG Grid.
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run check:i18n
|
||||
npx tsc -b
|
||||
npx vitest run
|
||||
```
|
||||
|
||||
Il controllo dei cataloghi segnala messaggi statici mancanti, interpolazioni
|
||||
incompatibili e traduzioni discordanti. Non può provare da solo la copertura di
|
||||
tutti i messaggi dinamici: completarlo con i test delle pagine e la verifica visiva.
|
||||
|
||||
La build verifica anche il CSS effettivamente generato: il reset Tailwind viene
|
||||
limitato al mount React e ai suoi popup con selettori ordinari, senza richiedere
|
||||
supporto browser a `@scope`. Mantenere letterali le classi dei due modi della shell
|
||||
per conservarle durante la rimozione del CSS inutilizzato. Le griglie usano il tema
|
||||
CSS esistente con i token light/dark; non mescolarlo con la nuova Theming API di AG Grid.
|
||||
|
||||
## Verifica prima del deploy server
|
||||
|
||||
### Acquisire prima le modifiche al repository Omics
|
||||
|
||||
Procedura aggiornata il 14 settembre 2026: acquisire il codice Omics da GitHub
|
||||
e integrarlo con il codice operativo del server. Non è richiesta alcuna replica
|
||||
del repository su altri servizi; l'eventuale copia è un'attività distinta del
|
||||
proprietario. Questa indicazione sostituisce le precedenti note di trasporto,
|
||||
anche se ancora presenti nei documenti storici del branch Omics.
|
||||
|
||||
La [consegna corrente a Codex sul server](server-codex-handoff.md) contiene i
|
||||
comandi esatti di acquisizione, gli SHA, i file da adeguare, la configurazione
|
||||
embedded/upstream, i test, i gate di rilascio e il rollback. Usarla come procedura
|
||||
ordinata per l'aggiornamento; le sezioni qui sotto restano il riepilogo tecnico.
|
||||
|
||||
Consegna GitHub riverificata: branch `codex/thothii-embedded-shell` di
|
||||
`https://github.com/Dallavilla-Tiziano/omics_portal.git`, SHA
|
||||
`fca10901a73666ca257d8f4cc4b77066295c400a`, incluso il commit funzionale
|
||||
`95154e179144e2453b37ef2a63a65d6f377e4cf8`. Il pull di ThothII non aggiorna
|
||||
Omics: il checkout del portale, normalmente `/home/chirone/omics_portal`, va
|
||||
verificato e integrato separatamente preservando le modifiche successive del server.
|
||||
|
||||
### Preparare il rilascio coordinato
|
||||
|
||||
1. Registrare SHA approvati di **entrambi** i repository, immagini precedenti,
|
||||
descriptor ThothII, file Compose/override e progetto realmente in uso. La testa
|
||||
del branch di lavoro non è automaticamente una revisione approvata di produzione.
|
||||
2. In un checkout di revisione separato, integrare Omics con il branch di rilascio
|
||||
concordato. Non fare merge nel checkout operativo con modifiche altrui.
|
||||
I file Omics da includere sono template Datamart Builder/topbar/base, asset
|
||||
fullscreen e cataloghi Django del branch; conservare la verifica server
|
||||
esistente in `kokoro/datamart_catalog_views.py` e le location Nginx protette.
|
||||
3. Eseguire dal checkout Omics i test isolati, non i test contro il database operativo:
|
||||
|
||||
```bash
|
||||
docker build -f test_support/thothii/Dockerfile -t omics-portal:thothii-shell-tests .
|
||||
docker run --rm --network none omics-portal:thothii-shell-tests
|
||||
```
|
||||
|
||||
4. Predisporre il descrittore ThothII embedded e il core upstream secondo la guida.
|
||||
Verificare che Nginx Omics possa raggiungere gli alias privati `thothii-core:8787`
|
||||
e `thothii-frontend:8080` e che non esista un ingresso non protetto al core.
|
||||
Non sovrascrivere rete, mount o autenticazione usando il Compose locale del Mac.
|
||||
5. Solo dopo il gate operatore, applicare le revisioni approvate seguendo il
|
||||
lifecycle dei due progetti. In Omics i servizi sono `web` e `nginx`: includere
|
||||
nel rebuild template, statici e cataloghi, mantenendo tutti gli override del
|
||||
server. Verificare la configurazione Nginx con `nginx -t` nel servizio e lo
|
||||
stato di entrambi. Non inventare opzioni Compose/progetto: usare quelle
|
||||
registrate al punto 1. Gli entrypoint del portale possono avere altri effetti
|
||||
operativi: questa modifica non richiede nuove migrazioni DB, ma non autorizza
|
||||
a bypassare i controlli del suo rilascio.
|
||||
6. Dopo l'aggiornamento del frontend, attendere la cache manifest Django (30 s)
|
||||
oppure usare l'invalidazione prevista dal portale; ricaricare e controllare
|
||||
config/asset/prefisso API prima di giudicare il risultato.
|
||||
7. Compilare la matrice seguente. In caso di errore ripristinare revisioni,
|
||||
immagini e configurazioni registrate, senza cancellare volumi. Il rollback
|
||||
deve conservare una coppia compatibile di template Omics e frontend ThothII.
|
||||
|
||||
La consegna GitHub è verificata; il deploy della revisione integrata
|
||||
Omics rimane da confermare dall'operatore. I test locali non attestano lo stato
|
||||
attuale del server remoto.
|
||||
|
||||
### Accettazione dell'integrazione
|
||||
|
||||
Usare la [matrice completa full/embedded e autenticazione](../testing/authentication-manual-acceptance.md),
|
||||
registrando per ogni prova revisione, ambiente e risultato. Non spuntare i casi
|
||||
IdP/Omics reali soltanto perché passano i test con risposte simulate.
|
||||
|
||||
Provare l'apertura dal menu Omics con un utente autorizzato e uno senza accesso;
|
||||
verificare assenza di un secondo login e di header ThothII, italiano/inglese già
|
||||
selezionati prima dell'apertura, tema, fullscreen e uscita con Esc. Ripetere con
|
||||
un menu o un form aperto, una bozza non inviata e una sessione esistente.
|
||||
|
||||
Verificare perdita dell'accesso, ritorno alla scheda e riconnessione degli eventi;
|
||||
distinguere questi casi dal rifiuto di una sola operazione. Controllare che una
|
||||
ripresa conservi la lingua salvata e che il reload non avvii una nuova generazione.
|
||||
Eseguire i test Omics nel suo ambiente Docker e includere gli aggiornamenti
|
||||
dei template, degli asset e dei cataloghi Django nel suo normale rebuild.
|
||||
|
||||
La verifica del codice e i test locali non costituiscono un deploy sul server
|
||||
di produzione. Usare il normale processo di rilascio per applicare entrambe le
|
||||
revisioni e annotare immagini, descrittore e revisioni realmente installate.
|
||||
@@ -73,9 +73,9 @@ only that run's safe stage, error code, and finish time; use `docker compose log
|
||||
corresponding service log.
|
||||
|
||||
The contract gives exact validation, exit code, and JSON rules in
|
||||
[Workspace preprocessing CLI](../contracts/workspace-preprocessing-cli.md). For Evidence source
|
||||
[Workspace preprocessing CLI](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/workspace-preprocessing-cli.md). For Evidence source
|
||||
forms and the schema-v4 descriptor contract, see
|
||||
[Workspace Evidence v3](../contracts/workspace-evidence-v3.md).
|
||||
[Workspace Evidence v3](https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/contracts/workspace-evidence-v3.md).
|
||||
|
||||
## Transport and revision rules
|
||||
|
||||
|
||||
@@ -1,695 +0,0 @@
|
||||
# Metadata Catalog di ThothII: ricognizione ThothAI e percorso incrementale
|
||||
|
||||
Data: 2026-08-26; aggiornato 2026-08-27
|
||||
Stato: ricognizione e progettazione completate; navigazione, CRUD Workspace Database, Catalog
|
||||
Table, Catalog Column, Catalog Relationship e sincronizzazione durevole dello schema implementati
|
||||
il 2026-08-27. Generazione AI e integrazione con il workflow core restano negli step successivi.
|
||||
|
||||
## Obiettivo
|
||||
|
||||
ThothII deve introdurre un contesto amministrativo separato, il **Metadata Catalog**, per gestire
|
||||
il database associato a ciascun workspace, la sua struttura fisica introspezionata e i metadati
|
||||
semantici oggi rappresentati da `schema/annotations.yaml`.
|
||||
|
||||
Il programma procede per step indipendenti. Il primo step ha aggiunto l'accesso dalla sidebar; il
|
||||
secondo ha sostituito la superficie vuota con il CRUD di configurazione, il PostgreSQL interno e i
|
||||
test di connessione; gli step successivi hanno aggiunto navigazione gerarchica, colonne, relazioni
|
||||
fisiche e sincronizzazione durevole dell'intero schema. Non introduce ancora generazione AI o
|
||||
integrazione con il workflow core.
|
||||
|
||||
Questa analisi usa come riferimento il working tree legacy osservato in
|
||||
`Thoth/ThothAI`. Non è stato verificato che quel contenuto corrisponda a una release o a un tag
|
||||
canonico; i percorsi e i comportamenti descrivono il sorgente disponibile il 2026-08-26.
|
||||
|
||||
## Decisioni già confermate
|
||||
|
||||
1. Ogni Workspace Database appartiene a un solo workspace tramite un `workspace_id` obbligatorio e
|
||||
univoco; un workspace può avere al massimo un Workspace Database. Poiché i workspace non sono
|
||||
righe del catalogo PostgreSQL, l'associazione è un riferimento logico validato contro
|
||||
`thoth-workspaces.yaml`, non una foreign key SQL.
|
||||
2. Il CRUD non crea né rinomina workspace. Identità e lista ordinata dei workspace restano
|
||||
autorevoli in `thoth-workspaces.yaml`; il catalogo conserva il loro identificatore stabile.
|
||||
3. La struttura fisica viene acquisita interrogando il database esterno tramite i dati di
|
||||
connessione registrati per il Workspace Database.
|
||||
4. I contenuti semantici equivalenti a `annotations.yaml` vengono generati con l'AI e conservati nel
|
||||
PostgreSQL interno.
|
||||
5. Per PSD è prevista l'importazione delle annotations esistenti. Gli altri database partiranno
|
||||
dalla struttura introspezionata e genereranno i metadati semantici da zero.
|
||||
6. `annotations.yaml` sarà sostituito anche come input del core in uno step futuro. Il repository è
|
||||
in fase di test e non è richiesta la conservazione delle sessioni esistenti durante il cutover.
|
||||
7. La gestione catalogo resta una superficie separata dal processo NL→SQL. La futura integrazione
|
||||
deve essere esplicita e non deve modificare fasi, gate o semantica del workflow.
|
||||
8. Il link iniziale è visibile agli utenti con `workspace.manage`, usa stato React locale e non
|
||||
introduce un router.
|
||||
9. La pagina iniziale è vuota, segue il tema, nasconde l'intera colonna core e non interrompe una
|
||||
sessione live. Le azioni di apertura, resume o creazione sessione riportano al core.
|
||||
10. La compatibilità con il modello ThothAI è semantica, non una copia letterale: configurazione e
|
||||
contenuti semantici sono campi relazionali mutabili, mentre identità e appartenenza della
|
||||
struttura fisica derivano dall'introspezione; i segreti restano nel secret store e lo stato dei
|
||||
job non viene mescolato ai dati amministrativi.
|
||||
11. Il CRUD amministra il Metadata Catalog e non esegue DDL sul database esterno, che resta
|
||||
read-only.
|
||||
12. La prima versione supporta PostgreSQL; il confine di introspezione dovrà permettere di
|
||||
aggiungere altri dialetti senza cambiare il modello del catalogo.
|
||||
13. I segreti dei Workspace Database riusano il secret store cifrato di ThothII. Il catalogo
|
||||
conserva riferimenti ai segreti e nessuna API, esportazione o log ne restituisce i valori.
|
||||
14. La UI usa AG Grid Community per la lista master e un pannello React separato per il dettaglio;
|
||||
non dipende dalle funzionalità master-detail di AG Grid Enterprise.
|
||||
15. Un Workspace Database il cui `workspace_id` scompare dal catalogo YAML non viene cancellato
|
||||
automaticamente: diventa orphaned e può soltanto essere recuperato, riassegnato o eliminato
|
||||
esplicitamente da un amministratore.
|
||||
16. La prima vertical slice gestisce configurazione del Workspace Database, riferimenti ai segreti,
|
||||
test di connessione e stato. La seconda gestisce le Catalog Table: la collezione e i nomi sono
|
||||
controllati dall'introspezione, mentre la descrizione curata è modificabile. Le slice successive
|
||||
hanno aggiunto Catalog Column, Catalog Relationship e sincronizzazione durevole dello schema.
|
||||
17. Il modello non conserva il `name` libero di ThothAI: nome e ID visualizzati appartengono al
|
||||
workspace YAML, mentre `database_name` identifica il database PostgreSQL esterno.
|
||||
18. Database management supporta i tre trasporti già riconosciuti da ThothII: `postgres_direct`,
|
||||
`rest_api` e `ssh_tunnel`. PSD rimane un solo Workspace Database: usa la connessione diretta sul
|
||||
server e l'endpoint REST in locale tramite una Database Binding specifica dell'installazione.
|
||||
Questo supporto non abilita automaticamente `ssh_tunnel` nel runtime NL→SQL.
|
||||
19. Una configurazione può essere salvata prima di una connessione riuscita. Il test separato
|
||||
produce uno stato `untested`, `reachable` o `failed`; attivazione e introspezione richiedono uno
|
||||
stato raggiungibile.
|
||||
20. Il CRUD e il test di connessione richiedono `database.manage`; inserimento e sostituzione dei
|
||||
segreti continuano a richiedere `workspace.secrets.manage`.
|
||||
21. Il Workspace Database e il modo di raggiungerlo sono entità distinte. Ogni catalogo di
|
||||
installazione conserva una sola Database Binding attiva per workspace: PSD usa `rest_api` in
|
||||
locale e `postgres_direct` sul server senza duplicare il Workspace Database.
|
||||
22. Nel modello finale il Metadata Catalog è autorevole per engine, `database_name`, schema,
|
||||
capacità e binding. Lo YAML resta autorevole per identità e contenuti del workspace; i campi
|
||||
DWH correnti saranno importati, confrontati e rimossi soltanto durante un cutover esplicito.
|
||||
23. La lista master è l'unione fra workspace YAML e record del catalogo: mostra workspace
|
||||
`unconfigured`, database configurati e record `orphaned`.
|
||||
24. Ogni introspezione registra le capability disponibili. Una capability `unavailable` non viene
|
||||
rappresentata come una collezione osservata ma vuota; REST può completare con successo anche
|
||||
quando indici o enum non sono supportati.
|
||||
25. Il Metadata Catalog non introduce snapshot, draft o pubblicazioni. Configurazione e contenuti
|
||||
semantici, inclusi quelli futuri generati dall'AI, sono normali campi modificabili; la struttura
|
||||
osservata cambia soltanto con una sincronizzazione esplicita.
|
||||
26. Il normale Delete elimina realmente il Workspace Database, la Database Binding e i relativi
|
||||
record catalogo e segreti. Non modifica il DWH esterno né il repository YAML; il workspace torna
|
||||
visibile nella lista master come `unconfigured`.
|
||||
27. La prima versione gestisce un solo schema obbligatorio per Workspace Database, identificato
|
||||
dalla coppia `database_name + schema`; per PSD la coppia è `postgres + datawarehouse`.
|
||||
28. I record mantengono soltanto `created_at`, `updated_at` e un contatore `version` per optimistic
|
||||
concurrency. Non esistono storico delle revisioni, rollback o audit applicativo delle modifiche.
|
||||
29. `workspace_databases` conserva soltanto UUID, `workspace_id` unique, engine, `database_name`,
|
||||
schema, timestamp e version. Il nome visualizzato appartiene al workspace YAML.
|
||||
30. Ogni Workspace Database ha al massimo una riga `database_bindings`. Una singola tabella usa
|
||||
check constraint dipendenti da `transport` per i campi direct, REST e SSH; non esiste un flag
|
||||
`active`, perché ciascuna installazione conserva una sola binding.
|
||||
31. `rest_api` configura il Thoth REST Connector tipizzato: base URL, autenticazione e TLS sono dati
|
||||
della binding, mentre path RPC e shape delle risposte appartengono al contratto applicativo e non
|
||||
sono liberamente configurabili.
|
||||
32. Il test connessione usa soltanto una configurazione già salvata ed è associato alla sua
|
||||
`version`. Ogni modifica della binding o dei segreti invalida il risultato precedente e riporta
|
||||
lo stato a `untested`.
|
||||
33. Password, API key e chiavi sono write-only: l'API espone soltanto `configured`, un campo vuoto
|
||||
conserva il valore esistente e la sostituzione è un'azione esplicita. Delete rimuove anche i
|
||||
segreti associati.
|
||||
34. La pagina usa AG Grid come master e un form React come detail, con sezioni Database, Connection
|
||||
e TLS/SSH condizionali. Non esiste un'azione globale `Add database`: ogni riga `unconfigured`
|
||||
offre `Configure catalog`, apre il form già vincolato a quello specifico workspace YAML e crea il
|
||||
record soltanto al Save; `workspace_id` non è selezionabile né modificabile.
|
||||
35. La grid mostra separatamente revisione/Evidence del workspace, binding runtime NL→SQL e
|
||||
configurazione del Metadata Catalog, oltre a database, schema, endpoint e ultimo aggiornamento.
|
||||
Su schermi piccoli il dettaglio occupa il pannello completo. Il cambio riga con modifiche non
|
||||
salvate e Delete richiedono conferma, senza conferma testuale tipizzata.
|
||||
36. La Database Binding conserva `connection_status`, `tested_version`, `last_tested_at`, un codice
|
||||
errore e un messaggio breve sanificato. Non conserva stack trace, DSN, credenziali o output grezzo
|
||||
del driver.
|
||||
37. Le API vivono sotto `/api/catalog`: list/create di `/databases`, get/patch/delete di
|
||||
`/databases/:id`, sostituzione dei segreti sotto `/databases/:id/secrets`, test connessione sotto
|
||||
`/databases/:id/test` e list/patch/sync delle tabelle sotto `/databases/:id/tables`.
|
||||
38. `GET /api/catalog/databases` restituisce l'intera master list unificata; AG Grid Community applica
|
||||
client-side ricerca, filtri e ordinamento. La prima versione non introduce paginazione server o
|
||||
funzionalità AG Grid Enterprise.
|
||||
39. Il Metadata Catalog vive nello stesso processo Fastify come modulo isolato con repository,
|
||||
service, route, diagnostica e readiness proprie. L'indisponibilità del catalogo non modifica
|
||||
sessioni, SSE o health del core e non giustifica ancora un microservizio separato.
|
||||
40. Il backend mantiene `pg@8.22.0` e aggiunge `kysely@0.29.5` per query e transazioni tipizzate. Le
|
||||
migrazioni Kysely sono timestampate, compilate con il backend ed eseguite da un comando
|
||||
`catalog:migrate` separato; l'applicazione non migra automaticamente il database all'avvio.
|
||||
41. Lo stack aggiunge un servizio interno `catalog-db` con volume persistente, ruolo runtime DML,
|
||||
ruolo migrator DDL e job one-shot `catalog-migrate`. Un catalogo indisponibile produce 503 sulle
|
||||
sole route catalogo.
|
||||
42. La prima vertical slice è amministrativa: scrive il catalogo ma non cambia ancora il runtime di
|
||||
sessioni e workflow, che continua a usare YAML e binding correnti fino al cutover esplicito.
|
||||
43. `Configure` precompila senza salvare engine, database e schema dal descriptor e i dati non
|
||||
sensibili dalla binding effettiva. L'amministratore verifica, inserisce i segreti e salva; non
|
||||
esiste importazione silenziosa.
|
||||
44. Unit e route test usano un repository fake; una suite PostgreSQL Testcontainers separata verifica
|
||||
migrazioni, constraint, transazioni, optimistic concurrency e cascade. SQLite ed emulatori non
|
||||
sono sostituti ammessi per questi test.
|
||||
45. La navigazione delle entità catalogo è gerarchica e senza scorciatoie globali: `Databases →
|
||||
Database → Overview | Tables → Table`. Non esistono una voce globale Tables, un filtro globale
|
||||
Database o una preselezione implicita; Columns continuerà sotto Table e Relationships sotto
|
||||
Database.
|
||||
46. Una Catalog Table conserva nome fisico, `source_comment`, descrizione curata nullable,
|
||||
`generated_description` nullable per lo step AI futuro, version e timestamp. La UI mostra come
|
||||
tre campi indipendenti senza fallback visivo: source comment read-only, generated description
|
||||
modificabile e description modificabile. I valori null restano celle e controlli vuoti.
|
||||
47. Le Catalog Table non possono essere aggiunte o rinominate manualmente. Un amministratore può
|
||||
però ripulire esplicitamente le proiezioni nel Metadata Catalog senza modificare il database
|
||||
esterno; `Sync tables` legge le tabelle PostgreSQL ordinarie e partizionate dello schema scelto,
|
||||
mentre viste e materialized view sono escluse.
|
||||
48. La sincronizzazione è esplicita. La scansione avviene fuori dalla transazione del catalogo; il
|
||||
diff viene applicato atomicamente soltanto se la version del Workspace Database è ancora quella
|
||||
sottoposta a scansione. Una scansione fallita non modifica il catalogo.
|
||||
49. Tabelle nuove vengono create, i commenti sorgente vengono aggiornati e quelle non più osservate
|
||||
vengono eliminate definitivamente. La rimozione di tabelle, colonne o relazioni richiede la
|
||||
conferma dell'esatto piano distruttivo; se il secondo scan produce una fotografia differente,
|
||||
l'applicazione richiede una nuova conferma.
|
||||
50. Un rename fisico è intenzionalmente delete più create e perde i metadati curati. Le colonne e
|
||||
relazioni dipendenti vengono eliminate in cascade insieme alla Catalog Table.
|
||||
51. L'introspezione vive nel modulo catalogo Fastify dietro un adapter. PostgreSQL diretto e tunnel
|
||||
SSH usano il catalogo `pg_catalog`; REST preferisce il contratto tipizzato
|
||||
`POST /rpc/schema_snapshot` e, quando quell'RPC non è esposto, usa come fallback compatibile una
|
||||
singola query read-only tramite `POST /rpc/run_query`. Entrambi i percorsi devono produrre la
|
||||
stessa fotografia v1 stretta descritta in `docs/contracts/catalog-schema-snapshot.md`.
|
||||
52. Test connessione e sincronizzazione sono serializzati per Workspace Database, hanno timeout e
|
||||
richiedono che la binding nella version corrente abbia un test `reachable` prima di qualsiasi
|
||||
Catalog Sync Run. La scansione asincrona ha un timeout separato, di default dieci minuti.
|
||||
53. Il tunnel SSH usa OpenSSH in modalità stdio `-W`, chiave privata e passphrase opzionale dal
|
||||
secret store, `known_hosts` obbligatorio, `StrictHostKeyChecking=yes`, agent e configurazione
|
||||
globale disabilitati. Non è ammesso TOFU. TLS PostgreSQL con CA e server name resta verificato
|
||||
anche attraverso il tunnel.
|
||||
54. In questo slice `ssh_tunnel` è una binding supportata da Database management per Test connection
|
||||
e Schema Sync. Il renderer e il runtime delle sessioni NL→SQL restano fuori scope e continuano a
|
||||
rifiutarla finché non verrà deciso il relativo cutover.
|
||||
55. I menu di azione a livello Workspace Database espongono separatamente `Synchronize tables`,
|
||||
`Synchronize relationships` e `Synchronize all`. Su una selezione di
|
||||
database lo scope scelto viene avviato per ogni database idoneo; non viene sostituito
|
||||
implicitamente con una sincronizzazione completa.
|
||||
56. Lo scope Columns è disponibile dalla grid Tables e limita la riconciliazione alle tabelle
|
||||
selezionate; la pagina Columns non espone azioni di sincronizzazione. La grid Tables espone
|
||||
`Synchronize columns` sulle tabelle selezionate.
|
||||
|
||||
## Correzione del modello mentale corrente
|
||||
|
||||
`schema/annotations.yaml` non contiene l'intero schema del database.
|
||||
|
||||
- `physical.yaml` è un artefatto derivato dall'introspezione. Contiene database, schema, timestamp,
|
||||
tabelle, colonne, tipi, nullability, default, primary key, commenti sorgente, esempi, foreign key
|
||||
fisiche e indici.
|
||||
- `annotations.yaml` contiene metadati curati: descrizioni e concetti delle tabelle; descrizioni,
|
||||
sinonimi, concetti, evidence, note e override `eligible` delle colonne; foreign key logiche.
|
||||
- Il rendering M-Schema fonde questi due input. Le annotations prevalgono sui commenti sorgente e
|
||||
le relazioni logiche vengono unite alle foreign key fisiche.
|
||||
|
||||
La sostituzione del solo file annotations non elimina automaticamente l'introspezione fisica. Il
|
||||
nuovo catalogo dovrà conservare una distinzione esplicita fra fatti osservati nel database e
|
||||
contenuto semantico modificabile.
|
||||
|
||||
## Architettura ThothII rilevante
|
||||
|
||||
### Autorità e revisionamento attuali
|
||||
|
||||
Il repository dei workspace contiene:
|
||||
|
||||
```text
|
||||
thoth-workspaces.yaml
|
||||
<workspace-id>/workspace.yaml
|
||||
<workspace-id>/schema/annotations.yaml
|
||||
<workspace-id>/evidence/**
|
||||
```
|
||||
|
||||
Il backend legge descriptor e annotations allo stesso commit Git. Durante l'attivazione valida il
|
||||
blob, lo copia atomicamente nello snapshot immutabile della revisione e registra commit, blob ID e
|
||||
digest. Le nuove sessioni vengono legate a quella revisione; resume e SQL salvato riaprono lo stesso
|
||||
snapshot.
|
||||
|
||||
Punti principali:
|
||||
|
||||
- `backend/src/workspaces/schema.ts`: descriptor v3 e singolo `dwh.database`/`dwh.schema`;
|
||||
- `backend/src/workspaces/git-repository.ts`: lettura sicura del blob annotations al commit;
|
||||
- `backend/src/workspaces/registry.ts`: validazione e attivazione atomica;
|
||||
- `backend/src/workspaces/annotations-sync.ts`: materializzazione revision-qualified;
|
||||
- `backend/src/workspaces/runtime-config-lease.ts`: binding dello snapshot al runtime;
|
||||
- `harness/tht/mschema/models.py`: contratti `PhysicalSchema` e `Annotations`;
|
||||
- `harness/tht/mschema/render.py`: fusione fisico/semantico;
|
||||
- `harness/tht/cli/vector_cmd.py`: indicizzazione schema in Qdrant.
|
||||
|
||||
### Consumatori da preservare al cutover futuro
|
||||
|
||||
Le annotations incidono oggi su:
|
||||
|
||||
- override `eligible` prima del campionamento LSH;
|
||||
- suggerimento, controllo e accettazione delle foreign key logiche;
|
||||
- descrizioni, concetti e sinonimi dei record schema in Qdrant;
|
||||
- retrieval delle tabelle e colonne candidate;
|
||||
- rendering M-Schema usato dal gate F4 e dalla generazione SQL;
|
||||
- digest della revisione accettata durante il preprocessing.
|
||||
|
||||
Il futuro cutover non potrà limitarsi a rimuovere il file: dovrà fornire al core lo stesso contenuto
|
||||
effettivo, con un'identità coerente e test di equivalenza. Poiché non occorre preservare le sessioni
|
||||
di test esistenti, non serve progettare compatibilità con i vecchi manifest, ma resta necessario
|
||||
evitare letture parziali o semanticamente incoerenti.
|
||||
|
||||
## Inventario ThothAI
|
||||
|
||||
### Modelli legacy
|
||||
|
||||
I modelli sono definiti in `Thoth/ThothAI/backend/thoth_core/models.py`.
|
||||
|
||||
#### `SqlDb`
|
||||
|
||||
Campi di connessione osservati:
|
||||
|
||||
- `name`;
|
||||
- `db_host`, `db_port`;
|
||||
- `db_type`;
|
||||
- `db_name`, `schema`;
|
||||
- `user_name`, `password`;
|
||||
- `db_mode`;
|
||||
- configurazione SSH e Informix opzionale.
|
||||
|
||||
Il modello contiene anche scope, JSON dello scope, ERD, direttive, campi GDPR, collegamento a
|
||||
`VectorDb` e numerosi campi di stato/task/log per lavori AI asincroni.
|
||||
|
||||
I tipi legacy dichiarati sono Informix, MariaDB, MySQL, Oracle, PostgreSQL, SQL Server e SQLite.
|
||||
Questo elenco non costituisce automaticamente un requisito per ThothII: il core corrente supporta
|
||||
PostgreSQL e l'estensione ad altri dialetti dovrà essere decisa separatamente.
|
||||
|
||||
#### `SqlTable`
|
||||
|
||||
- `name`;
|
||||
- `description`;
|
||||
- `generated_comment`;
|
||||
- foreign key obbligatoria a `SqlDb`, con cancellazione cascade.
|
||||
|
||||
#### `SqlColumn`
|
||||
|
||||
- `original_column_name` e alias `column_name`;
|
||||
- `data_format` normalizzato;
|
||||
- `column_description`;
|
||||
- `generated_comment`;
|
||||
- `value_description`;
|
||||
- stringhe denormalizzate `pk_field` e `fk_field`;
|
||||
- foreign key obbligatoria a `SqlTable`, con cancellazione cascade.
|
||||
|
||||
#### `Relationship`
|
||||
|
||||
Contiene quattro foreign key obbligatorie:
|
||||
|
||||
- `source_table` e `source_column`;
|
||||
- `target_table` e `target_column`.
|
||||
|
||||
Il form admin verifica che le tabelle appartengano allo stesso database e che ogni colonna
|
||||
appartenga alla tabella selezionata. Il database non impone però gli stessi check.
|
||||
|
||||
#### `Workspace`
|
||||
|
||||
ThothAI usa `Workspace.sql_db` come foreign key nullable verso `SqlDb`: un workspace seleziona un
|
||||
solo DB, mentre lo stesso DB può essere riusato da più workspace. ThothII adotterà invece una
|
||||
relazione uno-a-uno: `workspace_id` deve essere unico nel catalogo.
|
||||
|
||||
### Lacune dei constraint legacy
|
||||
|
||||
Non risultano constraint database-level per:
|
||||
|
||||
- unicità del nome database nel workspace;
|
||||
- unicità `(database, table name)`;
|
||||
- unicità `(table, column name)`;
|
||||
- unicità degli estremi di una relationship;
|
||||
- appartenenza degli estremi della relationship allo stesso database;
|
||||
- corrispondenza fra colonna e tabella dichiarata.
|
||||
|
||||
ThothII deve applicare queste invarianti sia nel database interno sia nel servizio applicativo. La
|
||||
sola validazione del form non è sufficiente perché API, import e job la possono aggirare.
|
||||
|
||||
### Django Admin e UX da replicare concettualmente
|
||||
|
||||
ThothAI espone il CRUD tramite il Django Admin standard, registrato da
|
||||
`backend/thoth_core/admin.py` e pubblicato su `/admin/`.
|
||||
|
||||
Capacità utili:
|
||||
|
||||
- lista database con ricerca per nome, host, tipo, database e schema;
|
||||
- fieldset separati per identità, connessione, autenticazione, SSH e stato;
|
||||
- lista tabelle filtrabile per database;
|
||||
- lista colonne filtrabile in cascata per database e tabella;
|
||||
- lista relazioni con estremi leggibili e filtri per database e tabelle;
|
||||
- form relazione con dropdown dipendenti database → tabella → colonna;
|
||||
- validazione degli estremi prima del salvataggio;
|
||||
- azioni separate per test connessione, introspezione, import/export e generazione AI;
|
||||
- azioni bulk sulle righe selezionate.
|
||||
|
||||
ThothII deve replicare i contratti di interazione e validazione, non il rendering server-side o i
|
||||
template Django.
|
||||
|
||||
### Introspezione legacy
|
||||
|
||||
`Thoth/ThothAI/backend/thoth_core/dbmanagement.py` usa `thoth-dbmanager` per:
|
||||
|
||||
1. costruire l'adapter del dialetto;
|
||||
2. acquisire tabelle;
|
||||
3. acquisire e normalizzare colonne e tipi;
|
||||
4. acquisire relazioni;
|
||||
5. creare le eventuali colonne mancanti necessarie alle relazioni;
|
||||
6. aggiornare i campi PK/FK denormalizzati.
|
||||
|
||||
Il comportamento è principalmente additivo: usa `get_or_create` o controlli `exists`, aggiorna
|
||||
alcuni commenti, ma non riconcilia in modo completo rename, rimozioni o drift. Non va copiato così
|
||||
com'è. Il processo ThothII implementato distingue scansione, differenze osservate e applicazione
|
||||
della nuova snapshot.
|
||||
|
||||
### Generazione AI legacy
|
||||
|
||||
ThothAI dispone di azioni e workflow per:
|
||||
|
||||
- commenti delle tabelle;
|
||||
- commenti delle colonne;
|
||||
- scope del database;
|
||||
- ERD Mermaid;
|
||||
- documentazione del database;
|
||||
- analisi GDPR.
|
||||
|
||||
Per il requisito attuale sono direttamente rilevanti descrizioni di tabelle e colonne, scope e
|
||||
metadati semantici. ERD, documentazione aggregata e GDPR sono estensioni future, non prerequisiti
|
||||
del CRUD iniziale.
|
||||
|
||||
La separazione `description`/`generated_comment` del legacy non offre versioning o approvazione
|
||||
robusti. Nei passi successivi andrà deciso se l'output AI è una proposta revisionabile o diventa
|
||||
immediatamente il valore editabile corrente.
|
||||
|
||||
### Import ed export legacy
|
||||
|
||||
ThothAI offre:
|
||||
|
||||
- CSV di database, tabelle, colonne e relazioni;
|
||||
- export di struttura per workspace;
|
||||
- import mediante `import_db_structure`;
|
||||
- script SQL dei commenti per più dialetti;
|
||||
- aggiornamento delle descrizioni colonna da CSV.
|
||||
|
||||
Il futuro import PSD dovrà leggere il contratto YAML corrente e convertirlo su chiavi naturali,
|
||||
non riutilizzare gli ID numerici Django. Deve essere idempotente e produrre un report di elementi
|
||||
creati, aggiornati, ignorati o non risolti.
|
||||
|
||||
## Comandi osservati in ThothAI
|
||||
|
||||
### Backend locale
|
||||
|
||||
Eseguiti da `Thoth/ThothAI/backend`:
|
||||
|
||||
```sh
|
||||
uv sync
|
||||
uv run python manage.py migrate
|
||||
uv run python manage.py createsuperuser
|
||||
uv run python manage.py runserver 8200
|
||||
uv run pytest
|
||||
```
|
||||
|
||||
Import catalogo legacy:
|
||||
|
||||
```sh
|
||||
uv run python manage.py import_db_structure --source local
|
||||
uv run python manage.py load_defaults --only-level 4 --source local
|
||||
```
|
||||
|
||||
Test mirati rilevanti:
|
||||
|
||||
```sh
|
||||
uv run pytest tests/test_relational_database_operations.py -v
|
||||
uv run pytest tests/test_ssh_tunnel_configuration.py -v
|
||||
```
|
||||
|
||||
### Stack Docker legacy
|
||||
|
||||
ThothAI dichiara `postgres:16-alpine` nel profilo `internal-db`, con volume persistente e
|
||||
healthcheck `pg_isready`.
|
||||
|
||||
```sh
|
||||
docker compose --profile internal-db up --build
|
||||
```
|
||||
|
||||
Il wrapper legacy abilita lo stesso profilo quando `POSTGRES_INTERNAL=true`:
|
||||
|
||||
```sh
|
||||
POSTGRES_INTERNAL=true ./docker-up.sh
|
||||
```
|
||||
|
||||
Questi comandi documentano il riferimento osservato; non sono comandi di installazione per
|
||||
ThothII.
|
||||
|
||||
## Cosa copiare in ThothII
|
||||
|
||||
### Parità necessaria
|
||||
|
||||
- gerarchia Workspace Database → Table → Column;
|
||||
- relazione strutturale fra colonne sorgente e destinazione;
|
||||
- navigazione e filtri dipendenti workspace/database/tabella;
|
||||
- test di connessione separato dal salvataggio;
|
||||
- introspezione esplicita e ripetibile;
|
||||
- descrizioni generate dall'AI ma modificabili dall'utente;
|
||||
- validazione cross-entity delle relazioni;
|
||||
- azioni di import/export senza segreti;
|
||||
- stato leggibile dei job lunghi;
|
||||
- PostgreSQL interno persistente con migrazioni esplicite;
|
||||
- test di CRUD, cardinalità, cascade/restrict, isolamento per workspace e idempotenza.
|
||||
|
||||
### Parità semantica con `annotations.yaml`
|
||||
|
||||
Il modello futuro deve poter rappresentare almeno:
|
||||
|
||||
- descrizione, concetti e note per tabella;
|
||||
- descrizione, sinonimi, concetti, evidence, note ed `eligible` per colonna;
|
||||
- foreign key logiche;
|
||||
- distinzione fra commento fisico osservato e descrizione curata;
|
||||
- provenienza del contenuto importato o generato.
|
||||
|
||||
L'eventuale esclusione di uno di questi campi deve essere una decisione esplicita perché cambia
|
||||
rendering, retrieval, LSH o SQL generation.
|
||||
|
||||
### Vincoli minimi da progettare
|
||||
|
||||
- `workspace_id` obbligatorio e unico sul Workspace Database, con esistenza validata contro il
|
||||
catalogo YAML dal servizio applicativo;
|
||||
- nome tabella unico nel database e schema appropriato;
|
||||
- nome colonna unico nella tabella;
|
||||
- relationship unica secondo il modello, anche per chiavi composite;
|
||||
- estremi della relationship nello stesso Workspace Database;
|
||||
- appartenenza certa della colonna alla tabella;
|
||||
- mutazioni aggregate transazionali;
|
||||
- gestione esplicita di concorrenza fra CRUD e introspezione.
|
||||
|
||||
## Cosa non copiare
|
||||
|
||||
- Django, Django Admin, Django ORM, DRF, template admin e frontend Next;
|
||||
- modello Workspace legacy e condivisione dello stesso DB fra più workspace;
|
||||
- password o passphrase come normali campi testuali;
|
||||
- password incluse in CSV o export completi;
|
||||
- token SSO inseriti nella query string;
|
||||
- migrazioni generate automaticamente all'avvio;
|
||||
- validazioni presenti soltanto nel form;
|
||||
- `pk_field` e `fk_field` testuali come fonte di verità;
|
||||
- duplicazione di tabella e colonna negli estremi senza constraint coerenti;
|
||||
- introspezione additiva che non segnala rename, delete o drift;
|
||||
- azioni admin che possono mostrare successo dopo output AI non valido;
|
||||
- dipendenza del workflow core dalla disponibilità della UI o del PostgreSQL amministrativo.
|
||||
|
||||
## Aspetti di sicurezza da non ereditare
|
||||
|
||||
L'export legacy della struttura include username e password in chiaro. Il modello conserva inoltre
|
||||
password, passphrase SSH e altri segreti in `CharField`; non è stata trovata cifratura applicativa,
|
||||
nonostante un testo admin affermi il contrario.
|
||||
|
||||
ThothII distingue i metadati di connessione dai riferimenti al secret store cifrato. In ogni caso:
|
||||
|
||||
- nessun endpoint o export deve restituire segreti;
|
||||
- log ed errori devono sanificare DSN e credenziali;
|
||||
- le credenziali di migrazione non devono essere disponibili al runtime CRUD;
|
||||
- il catalogo non deve riusare credenziali del DWH, delle sessioni o di Qdrant;
|
||||
- test connessione e introspezione devono usare timeout e privilegi read-only.
|
||||
|
||||
La binding REST corrente richiede una verifica prima del cutover: il renderer emette
|
||||
`ssl_ca_file`, mentre il modello Python espone `ssl_ca`; il percorso della CA privata potrebbe quindi
|
||||
non essere consumato. PSD richiede TLS con CA privata in locale, perciò questo disallineamento deve
|
||||
essere corretto e coperto da un test end-to-end prima di affidare il profilo REST al catalogo.
|
||||
|
||||
## Percorso incrementale
|
||||
|
||||
### Step 1: accesso alla superficie vuota
|
||||
|
||||
Implementato in questo worktree:
|
||||
|
||||
- pulsante `Database management` nella sidebar destra;
|
||||
- visibilità legata a `workspace.manage`;
|
||||
- superficie centrale React separata e vuota;
|
||||
- nessun router, endpoint, fetch o stato catalogo;
|
||||
- sessione e SSE conservati in background;
|
||||
- ritorno al core tramite creazione, apertura o resume di una sessione;
|
||||
- test frontend dedicati.
|
||||
|
||||
Comandi di verifica:
|
||||
|
||||
```sh
|
||||
cd frontend
|
||||
npx vitest run src/shell/AppShell.database-management.test.tsx
|
||||
npx vitest run src/shell/AppShell.new-session.test.tsx \
|
||||
src/shell/AppShell.session-target.test.tsx \
|
||||
src/shell/AppShell.session-mgmt.test.tsx
|
||||
npx tsc -b
|
||||
```
|
||||
|
||||
### Step 2: contratto di dominio e schema relazionale
|
||||
|
||||
Progettazione della vertical slice completata: Workspace Database, Database Binding, singolo schema,
|
||||
riferimenti al secret store, optimistic concurrency e capability per trasporto hanno contratti
|
||||
espliciti. Configurazione e contenuti semantici restano mutabili; la struttura fisica osservata è
|
||||
sincronizzata e non modificabile manualmente.
|
||||
|
||||
### Step 3: PostgreSQL interno e migrazioni
|
||||
|
||||
PostgreSQL interno con volume e ruoli runtime/migrator separati. Il modulo catalogo usa Kysely sopra
|
||||
il driver `pg`; le migrazioni compilate vengono applicate soltanto dal comando `catalog:migrate` e
|
||||
mai allo startup Fastify. Health, readiness e diagnostica restano dedicate; l'indisponibilità del
|
||||
catalogo non cambia `core /health` e non interrompe una sessione.
|
||||
|
||||
### Step 4: API CRUD
|
||||
|
||||
Contratti HTTP, autorizzazione, paginazione, filtri, errori, optimistic concurrency e transazioni.
|
||||
Gli endpoint dovranno vivere sotto un namespace catalogo e non riutilizzare le route sessione.
|
||||
|
||||
### Step 5: UI CRUD
|
||||
|
||||
Workspace Database, Catalog Table, Catalog Column e Catalog Relationship sono implementati con
|
||||
React/Vite e il design system ThothII.
|
||||
La navigazione è gerarchica e locale al database (`Overview | Tables`), senza menu o filtri globali
|
||||
per tipo di entità. La grid delle tabelle non offre Add o cancellazione della singola configurazione;
|
||||
le selezioni espongono invece la pulizia esplicita dei metadati. Il dettaglio full-width mantiene
|
||||
immutabili i fatti fisici e consente di modificare separatamente Description e Generated
|
||||
Description. Colonne e relazioni seguono la stessa gerarchia: Columns appartiene al dettaglio
|
||||
della tabella, Relationships al database. I valori descrittivi null sono mostrati come celle e
|
||||
campi vuoti, senza fallback visivi o placeholder `Not set` che nascondano quale sorgente è
|
||||
effettivamente valorizzata.
|
||||
|
||||
Le griglie che dispongono di azioni massive usano checkbox e una toolbar contestuale con conteggio,
|
||||
menu `Actions` e cancellazione della selezione. La selezione identifica ID espliciti, può essere
|
||||
accumulata attraverso i filtri e viene azzerata dopo successo, nuova sincronizzazione o uscita
|
||||
dalla pagina; un'azione è all-or-nothing se un elemento non è idoneo. I menu a livello database
|
||||
espongono gli scope fisici come azioni distinte: `Synchronize tables`, `Synchronize relationships`
|
||||
e `Synchronize all`. La grid Tables espone invece `Synchronize columns` per le tabelle selezionate;
|
||||
la pagina Columns non espone sincronizzazione. Le selezioni database aggiungono `Delete all tables` e
|
||||
`Delete all relationships`; le selezioni tabelle aggiungono `Delete all columns` e `Delete all
|
||||
relationships`. Queste operazioni sono atomiche, richiedono conferma e non modificano database
|
||||
esterno, binding, configurazione o segreti. Test connection resta un'azione distinta; griglie senza
|
||||
azioni non mostrano controlli di selezione inerti.
|
||||
|
||||
### Step 6: introspezione
|
||||
|
||||
Catalog Table, Catalog Column e Catalog Relationship sono implementate per PostgreSQL diretto,
|
||||
Thoth REST Connector e tunnel SSH. La scansione read-only è separata dalla transazione; una
|
||||
riconciliazione atomica crea, aggiorna i commenti sorgente ed elimina, dopo conferma, i fatti fisici
|
||||
assenti senza rendere modificabile manualmente la struttura osservata. Gli scope autorevoli sono
|
||||
Tables per database e Physical Relationships per database. Per Columns, `tableIds` vuoto include
|
||||
tutte le Catalog Table correnti, mentre una lista di ID limita lo scope al sottoinsieme esplicito;
|
||||
`Synchronize all` osserva tutti e tre gli scope in un unico snapshot e li riconcilia insieme. Tutti
|
||||
gli scope sono eseguiti come Catalog Sync Run durevoli in background, non attraverso implementazioni
|
||||
sincrone e asincrone separate. Un run che prevede cancellazioni conserva il diff, attende una
|
||||
conferma esplicita e verifica nuovamente lo snapshot prima dell'applicazione; se la sorgente è
|
||||
cambiata, invalida la conferma. Ogni applicazione è atomica e fail-closed: errori, timeout o
|
||||
capability non disponibili non producono aggiornamenti parziali.
|
||||
|
||||
PK e FK devono essere visibili sulle Catalog Column senza duplicare le stringhe denormalizzate di
|
||||
ThothAI. La posizione nella primary key è un fatto osservato della colonna; membership e conteggio
|
||||
FK sono proiezioni derivate dalle Catalog Relationship e dalle loro coppie ordinate, aggiornate
|
||||
nella stessa transazione di riconciliazione.
|
||||
|
||||
Ogni scope registra la versione della Database Binding osservata e l'istante dell'ultima
|
||||
sincronizzazione. Una modifica della binding conserva il catalogo precedente ma lo marca stale;
|
||||
solo un `Synchronize all` riuscito rende nuovamente corrente l'intero schema.
|
||||
|
||||
### Step 7: generazione AI dei metadati
|
||||
|
||||
Generated Description è una proposta distinta e modificabile: un revisore può correggerla prima
|
||||
di consolidarla esplicitamente come Description. Lo slice AI dovrà decidere e implementare anche
|
||||
alias semantici, descrizioni dei valori, sinonimi e concetti per tabelle e colonne, oltre alla
|
||||
gestione esplicita di errori e output non validi. La generazione AI e l'azione di consolidamento non
|
||||
appartengono allo slice di introspezione dello schema.
|
||||
|
||||
### Step 8: migrazione PSD
|
||||
|
||||
Import idempotente delle annotations PSD, riconciliazione contro la struttura introspezionata,
|
||||
report degli orfani e confronto semantico con il rendering corrente. Gli altri workspace non
|
||||
ricevono import legacy.
|
||||
|
||||
### Step 9: sostituzione dell'input core
|
||||
|
||||
Rimuovere la dipendenza da `annotations.yaml` soltanto dopo avere un contratto equivalente,
|
||||
test di rendering/search/Qdrant e una policy di disponibilità. Le sessioni di test esistenti
|
||||
possono essere eliminate, ma le nuove sessioni non devono osservare aggiornamenti parziali.
|
||||
Questo cutover è esplicitamente rinviato fino al completamento del database dei metadati. Il primo
|
||||
gate successivo obbligatorio sarà valutare l'integrazione del Catalog Schema Snapshot con il
|
||||
workflow core e lo schema-linking corrente; il rinvio non autorizza a dimenticare o assorbire
|
||||
implicitamente il lavoro in altri slice.
|
||||
|
||||
### Step 10: operazioni e accettazione
|
||||
|
||||
Backup/restore reale, diagnostica, metriche, permessi definitivi, hardening degli export e
|
||||
test di failure isolation fra catalogo e workflow. I Catalog Sync Run hanno un solo job attivo per
|
||||
Workspace Database, sono concorrenti fra database diversi e usano un lock persistente. Un pannello
|
||||
operativo non modale rimane visibile durante la navigazione del database, mostra fasi, contatori,
|
||||
tempo trascorso e log sanitizzato via SSE con polling di fallback, e offre Confirm, Cancel e Retry
|
||||
quando consentiti. Un restart marca `interrupted` i run rimasti attivi; il retry crea un nuovo run.
|
||||
Le modifiche ai metadati restano consentite durante la scansione e sono preservate dall'applicazione.
|
||||
Il worker gira inizialmente nello stesso servizio Fastify ma dietro un'interfaccia estraibile, con
|
||||
coda, lease e heartbeat persistiti nel catalog-db. I riepiloghi dei run non scadono; gli eventi
|
||||
dettagliati sono conservati per 30 giorni, mentre snapshot e diff completi vengono eliminati dopo
|
||||
la conclusione lasciando conteggi, decisioni e una sintesi sanitizzata dell'esito.
|
||||
|
||||
## Verifiche del core da conservare per il cutover
|
||||
|
||||
Comandi attuali rilevanti:
|
||||
|
||||
```sh
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace preprocess dwh \
|
||||
--workspace <id> --json
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace schema suggest-fks \
|
||||
--workspace <id> --json
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace schema check \
|
||||
--workspace <id> --json
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace schema accept \
|
||||
--workspace <id> --run <run-id> --yes --json
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace index-schema \
|
||||
--workspace <id> --json
|
||||
```
|
||||
|
||||
Suite che documentano il comportamento da preservare:
|
||||
|
||||
```sh
|
||||
cd backend
|
||||
npx vitest run test/workspaces-git-annotations.test.ts \
|
||||
test/registry-annotations.test.ts \
|
||||
test/annotations-sync.test.ts \
|
||||
test/workspace-runtime-config-lease.test.ts \
|
||||
test/workspace-preprocessing-service.test.ts
|
||||
npx tsc --noEmit -p .
|
||||
|
||||
cd ../harness
|
||||
.venv/bin/pytest -q \
|
||||
tests/test_annotations_root.py \
|
||||
tests/test_schema_fk_annotations.py \
|
||||
tests/test_mschema_render.py \
|
||||
tests/test_qdrant_cli_commands.py
|
||||
```
|
||||
|
||||
Questi test non implicano che la futura implementazione debba continuare a usare file YAML.
|
||||
Definiscono gli effetti semantici e le guardie da mantenere o sostituire consapevolmente.
|
||||
|
||||
## Decisioni rinviate
|
||||
|
||||
Le seguenti scelte non appartengono allo step 1:
|
||||
|
||||
- lifecycle dei riferimenti ai segreti durante sostituzione e cancellazione;
|
||||
- criteri per aggiungere dialetti successivi a PostgreSQL;
|
||||
- criteri per un'eventuale estensione futura a più schemi per database;
|
||||
- lifecycle e gestione amministrativa delle future Logical Relationship;
|
||||
- alias semantici, descrizioni dei valori, sinonimi e concetti prodotti o assistiti dall'AI;
|
||||
- formato e momento del cutover dal file al database interno;
|
||||
- permission definitiva separata da `workspace.manage`.
|
||||
|
||||
Ognuna sarà affrontata nel relativo step, senza anticipare scelte tecnologiche nel presente
|
||||
documento.
|
||||
@@ -1,251 +0,0 @@
|
||||
# AI-generated descriptions for Catalog Tables and Catalog Columns
|
||||
|
||||
## Problem Statement
|
||||
|
||||
ThothII already stores a Generated Description separately from the curated Description for Catalog
|
||||
Tables and Catalog Columns, but administrators cannot populate it with AI. ThothAI provides the
|
||||
useful core workflow—generate table and column comments from schema context and small real-data
|
||||
samples—but its execution, configuration, and interaction model cannot be copied directly into
|
||||
ThothII.
|
||||
|
||||
Administrators need an asynchronous workflow integrated into Database Management. They must be
|
||||
able to choose an installation-approved model, generate descriptions for selected or missing
|
||||
targets, observe understandable progress, stop or recover a stuck operation, review generated
|
||||
text, and explicitly consolidate it. The solution must retain ThothAI's practical simplicity and
|
||||
must not introduce a general job platform, model gateway, distributed scheduler, or competing
|
||||
user-facing CLI.
|
||||
|
||||
## Solution
|
||||
|
||||
Add Description Generation to Database Management as one installation-wide, sequential background
|
||||
run owned by the Fastify backend. The browser starts a run and remains responsive while the backend
|
||||
processes bounded requests one at a time. Each completion is delegated to a short-lived internal
|
||||
Python helper using LiteLLM. Models, their default, and any API-key secret references are declared in
|
||||
application setup YAML and are independent of both workspaces and Pi configuration.
|
||||
|
||||
Each valid result is written immediately to the target's Generated Description. A minimal run row
|
||||
and ordered text events provide status, counters, history, and a live log. A stopped or crashed run
|
||||
is not resumed automatically; completed results remain in place and Generate Missing supplies the
|
||||
simple recovery path. An Unlock action marks a stale recorded run interrupted only when no helper
|
||||
or backend generation loop is alive.
|
||||
|
||||
Prompts use catalog context and, when available, no more than five real rows and five representative
|
||||
non-null examples. Samples are transient and never logged or persisted. A valid inability to infer
|
||||
a description produces a standard application-localized value such as `Non generabile`; provider,
|
||||
timeout, and response-validation failures remain technical errors.
|
||||
|
||||
Generated text remains separate from Description until an administrator uses the existing
|
||||
checkbox selection and Actions control to consolidate it. Consolidation retains Generated
|
||||
Description and never writes comments to the external Workspace Database.
|
||||
|
||||
## User Stories
|
||||
|
||||
1. As an installation operator, I want to declare the models allowed for metadata generation in setup YAML, so that model availability is controlled centrally.
|
||||
2. As an installation operator, I want to declare one default metadata-generation model, so that administrators begin with a safe operational choice.
|
||||
3. As an installation operator, I want each model to reference its own API-key secret, so that credentials are not stored in workspaces or browser-visible settings.
|
||||
4. As an installation operator, I want metadata-generation models to remain independent of Pi models, so that changing this workflow cannot disrupt the core NL-to-SQL experience.
|
||||
5. As an installation operator, I want invalid model setup to fail validation clearly, so that the application does not start with ambiguous provider behavior.
|
||||
6. As a Catalog Administrator, I want generation controls to explain when no model is configured, so that I know why the action is unavailable.
|
||||
7. As a Catalog Administrator, I want to select an approved model from a selector initialized to the setup default, so that I control which model performs the work.
|
||||
8. As a Catalog Administrator, I want to generate descriptions for selected Catalog Tables, so that I can work on a focused part of the catalog.
|
||||
9. As a Catalog Administrator, I want to generate descriptions for selected Catalog Columns, so that I can work on individual fields without regenerating a whole table.
|
||||
10. As a Catalog Administrator, I want to generate all eligible descriptions for a Workspace Database, so that I can initialize a catalog in one operation.
|
||||
11. As a Catalog Administrator, I want to generate only missing descriptions, so that I can continue interrupted work without replacing completed proposals.
|
||||
12. As a Catalog Administrator, I want a full run to process Catalog Columns before their Catalog Tables, so that table descriptions can benefit from column descriptions.
|
||||
13. As a Catalog Administrator, I want generation to run asynchronously after I start it, so that the browser remains usable and progress is not tied to one HTTP request.
|
||||
14. As a Catalog Administrator, I want only one Description Generation Run active in the installation, so that provider traffic and operational behavior remain predictable.
|
||||
15. As a Catalog Administrator, I want a second start attempt to return a clear conflict, so that I cannot accidentally overlap generation runs.
|
||||
16. As a Catalog Administrator, I want synchronization, cleanup, consolidation, and edits for the target Workspace Database blocked during generation, so that the simple sequential run sees stable catalog state.
|
||||
17. As a Catalog Administrator, I want to see the run's model, scope, status, counters, and timestamps, so that I understand what is happening.
|
||||
18. As a Catalog Administrator, I want a chronological text log, so that I can follow completed targets and diagnose errors.
|
||||
19. As a Catalog Administrator, I want live log updates with a polling fallback, so that temporary SSE problems do not hide run progress.
|
||||
20. As a Catalog Administrator, I want completed and interrupted runs to remain inspectable, so that I can understand prior activity.
|
||||
21. As a Catalog Administrator, I want to stop an active run, so that I can halt an incorrect or unexpectedly costly operation.
|
||||
22. As a Catalog Administrator, I want stopping a run to terminate its current model helper and prevent later targets from starting, so that stop has prompt operational effect.
|
||||
23. As a Catalog Administrator, I want valid results completed before a stop or failure to remain saved, so that useful work is not discarded.
|
||||
24. As a Catalog Administrator, I want a run left active by a backend restart to become interrupted, so that the UI does not claim nonexistent work is still running.
|
||||
25. As a Catalog Administrator, I want to unlock a stale active run when no generation process is alive, so that an erroneous recorded lock cannot block future work.
|
||||
26. As a Catalog Administrator, I want Unlock rejected while a live generation process exists, so that recovery cannot create an overlapping run.
|
||||
27. As a Catalog Administrator, I want Generate Missing to continue after interruption, so that recovery does not require a special resume mechanism.
|
||||
28. As a Catalog Administrator, I want one retry for a transient model failure, so that a brief provider fault does not immediately lose a batch.
|
||||
29. As a Catalog Administrator, I want the run to fail after three consecutive technical failures, so that a broken provider does not generate an unbounded stream of attempts.
|
||||
30. As a Catalog Administrator, I want a successful request to reset the consecutive-failure count, so that isolated errors do not prematurely stop a useful run.
|
||||
31. As a Catalog Administrator, I want a completed-with-errors result when isolated batches fail but the run reaches its end, so that partial problems remain visible.
|
||||
32. As a Catalog Administrator, I want no automatic fallback to a different model, so that the selected model remains truthful and predictable.
|
||||
33. As a Catalog Administrator, I want malformed or ambiguous model output rejected without writing it, so that descriptions cannot be assigned to the wrong target.
|
||||
34. As a Catalog Administrator, I want an inability to infer a description represented by standard localized text, so that every valid outcome is understandable in the workspace language.
|
||||
35. As a Catalog Administrator, I want technical failures kept distinct from non-generatable outcomes, so that provider problems are not mistaken for catalog knowledge.
|
||||
36. As a Catalog Administrator, I want generated prose written in the workspace language, so that it matches the catalog's intended audience.
|
||||
37. As a Catalog Administrator, I want generated text stored separately from curated Description, so that AI output remains a reviewable proposal.
|
||||
38. As a Catalog Administrator, I want to edit a Generated Description manually, so that I can improve a proposal before consolidation.
|
||||
39. As a Catalog Administrator, I want to select one or more tables or columns and run “Move generated description to Description” from the existing Actions control, so that review remains integrated into the current grids.
|
||||
40. As a Catalog Administrator, I want consolidation to retain the Generated Description, so that I can still see the proposal from which the curated text was copied.
|
||||
41. As a Catalog Administrator, I want selected records without a Generated Description skipped and reported, so that the bulk action does not erase curated text.
|
||||
42. As a Catalog Administrator, I want consolidation and generation to modify only the Metadata Catalog, so that no external database comment is changed.
|
||||
43. As a Catalog Administrator, I want prompts to use schema facts and existing catalog text, so that generated descriptions are grounded in available metadata.
|
||||
44. As a Catalog Administrator, I want prompts to use at most five real source rows and five representative values when available, so that the model has useful examples without unbounded disclosure.
|
||||
45. As a Catalog Administrator, I want to be warned that real source samples are sent to the selected provider, so that I can make an informed disclosure decision.
|
||||
46. As a Catalog Administrator, I want sampled rows and values excluded from persistence and logs, so that operational history does not become a secondary data store.
|
||||
47. As a security operator, I want API keys, prompts, samples, and complete provider payloads redacted from logs, so that diagnostics do not leak secrets or source data.
|
||||
48. As a support operator, I want concise per-target and per-batch event messages, so that failures can be diagnosed without provider-specific internals.
|
||||
49. As an authorized administrator, I want all generation, cancellation, unlock, and consolidation actions protected by database-management permission, so that ordinary users cannot mutate catalog metadata.
|
||||
50. As an unauthorized user, I want generation controls hidden or disabled and API calls rejected, so that frontend visibility is not treated as authorization.
|
||||
51. As an operator, I want setup changes to take effect after an application restart, so that configuration lifecycle remains simple and explicit.
|
||||
52. As a product owner, I want the first release to avoid queues, parallel calls, distributed locks, and automatic resume, so that effort remains focused on generating and reviewing useful descriptions.
|
||||
|
||||
## Implementation Decisions
|
||||
|
||||
- The Fastify backend owns one installation-wide Description Generation Run and its sequential
|
||||
processing loop. It does not delegate lifecycle ownership to Pi or Python.
|
||||
- A Description Generation Run has one of `queued`, `running`, `completed`,
|
||||
`completed_with_errors`, `cancelled`, `failed`, or `interrupted`. It stores the Workspace
|
||||
Database, requested scope, selected model identifier, workspace language, progress counters,
|
||||
timestamps, and an optional final error summary.
|
||||
- Ordered Description Generation Events store timestamp, severity, and safe human-readable text.
|
||||
When an event identifies a target, it uses the object type and qualified physical name, such as
|
||||
`Column "patients.birth_date"` or `Table "patients"`; catalog UUIDs remain internal identifiers.
|
||||
No durable per-target jobs, model invocation rows, prompt snapshots, sample snapshots, leases,
|
||||
heartbeats, registry revisions, or provenance chains are introduced.
|
||||
- Starting a run schedules an in-process background loop and returns the run immediately. The API
|
||||
exposes start, run/history lookup, event listing and streaming, cancellation, stale-run unlock,
|
||||
and the safe list of configured model choices. There are no retry-item or resume endpoints.
|
||||
- One in-memory generation manager enforces the installation-wide active-run rule. The existing
|
||||
Catalog Operation Coordinator reserves the target Workspace Database for the duration of the
|
||||
run, without being generalized into a new operation framework.
|
||||
- On backend startup, persisted `queued` or `running` Description Generation Runs become
|
||||
`interrupted`. The application performs no automatic replay or resume.
|
||||
- Unlock succeeds only when no live generation loop or helper child exists. It marks the stale run
|
||||
interrupted and releases the local reservation; it is not a distributed lock recovery protocol.
|
||||
- Each model completion uses a short-lived Python helper backed by LiteLLM. Structured input is
|
||||
supplied over stdin, structured output alone is emitted on stdout, diagnostics use stderr, and
|
||||
the helper can be terminated by cancellation.
|
||||
- A completion request contains no more than ten targets. Requests run one at a time. The helper
|
||||
performs at most one retry for a transient technical failure.
|
||||
- Three consecutive model-request failures fail the run. A successful request resets that count.
|
||||
Isolated exhausted failures may be logged and skipped, producing `completed_with_errors` if the
|
||||
run later reaches its end.
|
||||
- Every valid generated or non-generatable result is applied immediately to Generated Description.
|
||||
Earlier writes are retained after cancellation, interruption, or later failure.
|
||||
- A response must identify requested targets unambiguously and classify each returned result as
|
||||
generated or non-generatable. Duplicate, unknown, missing, or malformed mappings cause a
|
||||
technical request failure and no result from that ambiguous response is applied.
|
||||
- The parser also tolerates one JSON object enclosed by one complete `json` code fence, because
|
||||
some supported models add that formatting despite the prompt. Any prose outside the fence,
|
||||
multiple payloads, or malformed/ambiguous mappings remain invalid.
|
||||
- The application supplies localized standard non-generatable text. Provider wording is not used
|
||||
as the standard value, and technical errors never write that value.
|
||||
- A full-database run generates eligible Catalog Columns before Catalog Tables. Generate Missing
|
||||
excludes targets whose Generated Description is already non-empty; all-generation may replace
|
||||
existing generated proposals only after the initiating action makes that scope explicit.
|
||||
- Model choices are declared under a metadata-generation section in installation setup YAML. Each
|
||||
choice has a stable identifier, display label, LiteLLM provider/model settings, optional endpoint
|
||||
settings, and an optional environment-secret reference for its API key. The reference may be
|
||||
omitted only when an explicit endpoint is configured for unauthenticated access. One identifier
|
||||
is the default.
|
||||
- An explicit endpoint may set `disableThinking: true`; the helper translates it only to the
|
||||
Qwen-compatible chat-template switch needed to keep the response within the strict JSON contract.
|
||||
- Metadata-generation setup is separate from application settings for Pi and from workspace
|
||||
`llm_policy`. Raw keys never enter setup YAML, the catalog database, API responses, process
|
||||
arguments, or event text. Configuration reload is restart-only.
|
||||
- If setup defines no usable model, the safe model-list response is empty and the UI disables
|
||||
generation with an explanation. The backend still rejects direct generation attempts.
|
||||
- Prompt construction treats schema names, comments, descriptions, and values as untrusted data.
|
||||
It requests output in the workspace language and separates instructions from catalog content.
|
||||
- A request may contain up to five real source rows and up to five representative distinct,
|
||||
non-null values for relevant columns. Inputs are bounded before prompt construction and are not
|
||||
persisted or logged.
|
||||
- The UI discloses that real data can be sent to the selected provider. A future Sensitive Data
|
||||
Policy will classify values and exclude or anonymize protected data; that policy is not silently
|
||||
approximated in this slice.
|
||||
- The generation UI reuses Database Management's table and column selections, model selector,
|
||||
Actions control, run drawer conventions, SSE delivery, and polling fallback where practical.
|
||||
Visual parity with Catalog Sync Run logs is not required.
|
||||
- The consolidation action copies each selected, non-empty Generated Description into Description
|
||||
in a catalog transaction, retains Generated Description, skips empty proposals, and reports
|
||||
copied and skipped counts. It never writes to the external Workspace Database.
|
||||
- Generation, cancellation, unlock, and consolidation require the existing database-management
|
||||
permission and are validated by the backend independently of UI state.
|
||||
- No user-facing generation CLI is added. The Python process is an internal completion adapter,
|
||||
not an operator surface or a long-lived service.
|
||||
|
||||
## Testing Decisions
|
||||
|
||||
- Tests assert externally observable behavior rather than private loop structure, process timing,
|
||||
or LiteLLM implementation details.
|
||||
- The primary and highest test seam is the Fastify catalog API with a test PostgreSQL catalog and
|
||||
an injected fake Model Completer. It verifies complete paths through authorization, run
|
||||
persistence, sequential processing, event delivery, Generated Description updates, and final
|
||||
status without contacting a real provider.
|
||||
- API tests cover each generation scope, column-before-table order, the ten-target request bound,
|
||||
model validation, one-active-run conflict, target-database exclusion, cancellation, startup
|
||||
interruption, Unlock safeguards, Generate Missing, partial success, consecutive failure
|
||||
handling, non-generatable localization, malformed responses, redacted events, and permissions.
|
||||
- Catalog repository integration tests verify the migration, run and event ordering, active-run
|
||||
constraint, immediate description writes, history queries, startup interruption, and bulk
|
||||
consolidation behavior against PostgreSQL.
|
||||
- The Python helper has a small black-box contract suite using a simulated LiteLLM adapter. It
|
||||
verifies stdin/stdout framing, pristine stdout, stderr diagnostics, normalized success and
|
||||
failure output, one transient retry, secret redaction, and termination behavior.
|
||||
- Setup-validation tests cover duplicate model identifiers, missing or unknown defaults, malformed
|
||||
provider settings, missing secret references, safe public model projection, and strict separation
|
||||
from Pi and workspace model settings.
|
||||
- Database Management tests use the existing browser-level component seam with MSW. They verify
|
||||
model selection and default, selected/all/missing actions, disabled state without models, running
|
||||
progress and logs, polling recovery, cancellation, Unlock visibility, terminal summaries,
|
||||
generated-text refresh, and selected consolidation with copied/skipped counts.
|
||||
- Existing Catalog Sync Run route, repository, SSE, and drawer tests are prior art for asynchronous
|
||||
status and event behavior. Existing catalog table/column editing and Database Management tests
|
||||
are prior art for optimistic catalog updates, permissions, selection, and action controls.
|
||||
- One required manual acceptance gate, outside deterministic CI, uses the installation's configured
|
||||
default model and a disposable PostgreSQL database containing only invented data. Its application
|
||||
credentials are read-only. It generates Italian text for one Catalog Column and one Catalog
|
||||
Table, verifies their Generated Description, inspects the safe activity log, confirms that no key
|
||||
or sample value is exposed, and consolidates one selected result. If the configured secret is not
|
||||
available, acceptance stops without exposing or requesting the key in conversation.
|
||||
- Delivery includes a strict MkDocs build executed through repository-managed, reproducible
|
||||
documentation dependencies rather than globally installed Python packages. A readable direct
|
||||
dependency file is retained, a complete transitive lock is generated with `uv`, and one canonical
|
||||
repository command performs the strict build from that lock.
|
||||
- Successful real-provider acceptance is recorded in a short sanitized report under
|
||||
`docs/testing/`. It identifies the model and checks performed but contains no credentials,
|
||||
prompts, source samples, complete provider payloads, or generated database values.
|
||||
- No tests are added for worker queues, parallel generation, distributed locking, multi-replica
|
||||
recovery, automatic resume, cost accounting, or model fallback because those behaviors are out
|
||||
of scope.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Reusing Pi to execute Description Generation or changing Pi's model configuration.
|
||||
- A shared Installation Model Registry, model gateway, long-lived Python sidecar, or provider
|
||||
management platform.
|
||||
- A user-facing generation CLI.
|
||||
- Parallel model calls, worker queues, adaptive rate limiting, distributed locks, leases,
|
||||
heartbeats, automatic resume, or multi-replica execution.
|
||||
- Durable target jobs, invocation history, prompts, samples, token usage, cost accounting,
|
||||
provenance chains, target snapshots, or advanced retention controls.
|
||||
- Automatic retry or resume of individual targets beyond one technical helper retry and a new
|
||||
Generate Missing run.
|
||||
- Automatic fallback to a different model.
|
||||
- Writing generated text into comments of the external Workspace Database.
|
||||
- Generating logical relationships or other catalog metadata beyond Catalog Table and Catalog
|
||||
Column descriptions.
|
||||
- Implementing the Sensitive Data Policy. Its definition and exclusion/anonymization behavior are
|
||||
a required follow-up improvement.
|
||||
- Generalizing the log viewer across unrelated metadata operations. That broader concern remains
|
||||
related to Gitea issue #2.
|
||||
|
||||
## Further Notes
|
||||
|
||||
- The design deliberately follows ThothAI's proven simple workflow while adapting it to ThothII's
|
||||
asynchronous browser interaction, setup ownership, and existing Generated Description model.
|
||||
- The source-sampling disclosure is a release requirement, not merely documentation for operators.
|
||||
- `completed_with_errors` is reserved for a run that reaches the end after isolated technical
|
||||
failures. Three consecutive failures end the run as `failed`.
|
||||
- Successful values are their own recovery record: after interruption, Generate Missing naturally
|
||||
skips them without needing replay state.
|
||||
- The implementation is available without a feature flag once the catalog migration and valid
|
||||
setup are present. With no configured model, the feature remains visibly unavailable rather than
|
||||
partially initialized.
|
||||
- The final manual gate is intentionally narrow: one real-provider run covers one Catalog Column
|
||||
and one Catalog Table, generated Italian text, safe events, and one consolidation. Automated
|
||||
tests remain the evidence for All, Missing, Stop, restart interruption, Unlock, and failure paths.
|
||||
@@ -1,173 +0,0 @@
|
||||
# AI catalog description generation
|
||||
|
||||
Status: simplified design, API, persistence, test seams, and delivery tickets accepted.
|
||||
|
||||
## Objective
|
||||
|
||||
Bring ThothAI's useful AI comment-generation workflow into the ThothII Metadata Catalog without
|
||||
turning it into a general job platform. Administrators can generate editable descriptions for
|
||||
catalog tables and columns, inspect progress, stop a run, recover a stale run, and explicitly copy
|
||||
approved generated text into the curated Description field.
|
||||
|
||||
The implementation is UI/API only. There is no user-facing generation command.
|
||||
|
||||
## ThothAI behavior retained
|
||||
|
||||
- Generate descriptions for selected tables, selected columns, missing descriptions, or all
|
||||
eligible targets.
|
||||
- Generate columns before their containing table when running the full workflow, so table prompts
|
||||
can benefit from the resulting column descriptions.
|
||||
- Process bounded batches of at most ten targets, one model request at a time.
|
||||
- Include schema context, existing catalog text, up to five real source rows, and up to five
|
||||
representative non-null values when available.
|
||||
- Keep generated text separate from the curated Description until an administrator consolidates
|
||||
it.
|
||||
- Use the existing table and column checkboxes plus the Actions selector to copy Generated
|
||||
Description into Description for one or more selected records. The generated value is retained.
|
||||
- Store a localized standard value such as `Non generabile` when a valid model response says that
|
||||
a description cannot be inferred.
|
||||
|
||||
Unlike ThothAI, every generation action is asynchronous from the browser's perspective and exposes
|
||||
a persistent, readable activity log.
|
||||
|
||||
## Minimal architecture
|
||||
|
||||
The Fastify backend owns the run lifecycle and sequential loop. It starts one short-lived Python
|
||||
helper for each model completion. The helper uses LiteLLM, accepts structured input on stdin,
|
||||
returns structured output on stdout, and writes diagnostics only to stderr.
|
||||
|
||||
This is preferred over reusing Pi. Pi remains the interactive NL-to-SQL orchestration surface,
|
||||
whereas description generation is a bounded batch transformation with no conversational state or
|
||||
human gate. A LiteLLM helper avoids inventing a Pi session protocol for a task that needs one
|
||||
request and one structured response.
|
||||
|
||||
There is no Python daemon, model gateway, queue service, worker pool, or generation CLI. Python is
|
||||
already a core implementation language in ThothII's harness and core image; this helper does not
|
||||
introduce a new runtime family.
|
||||
|
||||
## Run lifecycle and exclusion
|
||||
|
||||
- At most one Description Generation Run may be queued or running in the installation.
|
||||
- Start returns immediately after creating the run and scheduling the in-process backend loop.
|
||||
- Requests are sequential; there is no parallel provider traffic.
|
||||
- The target Workspace Database is reserved through the existing in-memory catalog-operation
|
||||
coordinator. Synchronization, cleanup, consolidation, and direct catalog edits for that database
|
||||
are rejected while generation is active.
|
||||
- A second generation start is rejected with a conflict response.
|
||||
- Stop terminates the current helper process, stops further targets, and marks the run cancelled.
|
||||
- Backend startup marks any queued or running generation row interrupted. It does not resume work.
|
||||
- Generate Missing is the normal manual continuation mechanism because successful values were
|
||||
already saved.
|
||||
- Unlock is available only when the backend has no live generation process; it marks a stale
|
||||
recorded run interrupted and clears the local reservation.
|
||||
|
||||
This is intentionally a single-process policy. Multi-replica coordination is out of scope.
|
||||
|
||||
## Persistence
|
||||
|
||||
Persist only:
|
||||
|
||||
- a Description Generation Run with database, scope, selected model, language, status, counters,
|
||||
timestamps, and an optional final error summary;
|
||||
- ordered Description Generation Events containing timestamp, level, and human-readable text;
|
||||
- each successful or non-generatable result directly in the target's Generated Description.
|
||||
|
||||
Do not add per-target job rows, invocation history, prompt or sample snapshots, provider cost
|
||||
accounting, leases, heartbeats, registry revisions, or generated-description provenance. The event
|
||||
log is operational evidence, not a replay mechanism.
|
||||
|
||||
## Model setup
|
||||
|
||||
Selectable models and their default belong to application setup YAML, not to a workspace. Each
|
||||
entry supplies a stable display identifier, LiteLLM provider/model information, optional endpoint
|
||||
settings, and—unless that explicit endpoint is unauthenticated—a reference to an installation
|
||||
secret containing the API key. Keyless entries without an explicit endpoint are invalid. Raw keys must not be
|
||||
stored in the YAML, database, frontend, events, or process arguments.
|
||||
An explicit endpoint may opt into `disableThinking: true` when its Qwen-compatible chat template
|
||||
would otherwise place reasoning text around the required JSON result.
|
||||
|
||||
This metadata-generation configuration is independent of the existing Pi provider/model settings
|
||||
and workspace `llm_policy`. A setup change takes effect after application restart. If no model is
|
||||
configured, generation controls are disabled with an explanatory message.
|
||||
|
||||
The browser receives only the selectable identifiers and labels. The selected value defaults to
|
||||
the setup default and is validated again by the backend when a run starts.
|
||||
|
||||
## Prompt inputs and outputs
|
||||
|
||||
Targets are grouped in model requests of at most ten. Prompts distinguish instructions from
|
||||
untrusted schema names, comments, descriptions, and sampled values. A response must map every
|
||||
returned result to a requested target and classify it as generated or non-generatable. Missing,
|
||||
duplicate, unknown, or malformed target results make that request a technical failure rather than
|
||||
silently writing ambiguous text.
|
||||
One complete `json` code fence around the object is tolerated for model compatibility; prose
|
||||
outside it, multiple payloads, and ambiguous mappings are still rejected.
|
||||
|
||||
For a complete database run, eligible columns are processed before tables. A table request can use
|
||||
the current Generated Description or Description of its columns. The output language is the
|
||||
workspace language; the standard non-generatable text is localized by the application rather than
|
||||
trusted to arbitrary model wording.
|
||||
|
||||
Up to five source rows and five representative examples may be sent to the provider and are never
|
||||
persisted. Delivery must call out this disclosure. A follow-up Sensitive Data Policy will define
|
||||
which values are excluded or anonymized.
|
||||
|
||||
## Errors, retry, and logs
|
||||
|
||||
The helper performs at most one retry for a transient technical provider failure. A final failed
|
||||
request produces an error event and increments the consecutive-error count. The run stops as
|
||||
failed after three consecutive technical failures; any successful request resets the count. There
|
||||
is no automatic fallback to another model.
|
||||
|
||||
Valid non-generatable outcomes are results, not technical errors. Successful results from earlier
|
||||
requests remain stored when a later request fails or the run is stopped.
|
||||
|
||||
The UI shows status, counters, selected model, start/end times, and a chronological text log. Live
|
||||
delivery may reuse the existing SSE infrastructure with polling as fallback; exact visual parity
|
||||
with synchronization logs is not required. Logs must not contain API keys, prompts, source sample
|
||||
values, or full provider payloads.
|
||||
|
||||
## Explicitly deferred complexity
|
||||
|
||||
- shared model registry or cutover of Pi configuration;
|
||||
- long-lived Python sidecar or internal HTTP model gateway;
|
||||
- generic catalog-operation kernel;
|
||||
- durable target items, invocation records, target snapshots, or provenance chains;
|
||||
- distributed locks, leases, heartbeats, worker queues, automatic resume, or multi-replica support;
|
||||
- parallel calls, adaptive rate limiting, cost estimation, advanced metrics, or model fallback;
|
||||
- user-facing generation CLI;
|
||||
- automatic writeback to comments in the external database;
|
||||
- Sensitive Data Policy implementation, which remains a required improvement after this slice.
|
||||
|
||||
## Delivery tracking
|
||||
|
||||
The accepted specification is Gitea issue #4 and the implementation is split into issues #5–#11.
|
||||
Each ticket is a bounded vertical slice with explicit Gitea dependencies. Implementation proceeds
|
||||
from the unblocked frontier, using a fresh subagent context for each ticket; integration and final
|
||||
verification remain centralized so later slices cannot silently reopen the deferred platform
|
||||
features above.
|
||||
|
||||
Issue #4 remains open until delivery completes four final gates: the stale Compose service-set
|
||||
contract is corrected in its own commit; documentation dependencies are repository-managed and a
|
||||
strict MkDocs build passes; one narrow real-provider acceptance run succeeds against non-sensitive
|
||||
test data; and a separate, non-blocking Sensitive Data Policy design ticket is linked as required
|
||||
follow-up work.
|
||||
|
||||
The documentation toolchain retains a readable direct-dependency input, adds a complete lock
|
||||
generated with `uv`, and exposes one canonical strict-build command. Real-provider acceptance uses
|
||||
the installation's configured default model and a disposable PostgreSQL database seeded only with
|
||||
invented values and accessed read-only by the application. A missing protected model secret stops
|
||||
the gate without disclosing it. The successful gate is captured in a sanitized report under
|
||||
`docs/testing/` without prompts, samples, full generated values, payloads, or credentials.
|
||||
|
||||
Delivery is organized as four reviewable commits: the stale Compose contract correction, the
|
||||
reproducible documentation toolchain, the AI-description feature, and—only after acceptance—the
|
||||
sanitized acceptance report. A failed real-provider gate does not invalidate already verified
|
||||
commits, but issue #4 remains open and no acceptance report claims success. Application defects are
|
||||
fixed and reverified; missing configuration or provider unavailability is recorded and retried.
|
||||
|
||||
After every gate passes, the existing `codex/db-management` branch is pushed to its configured
|
||||
origin without introducing a new pull-request workflow, then issue #4 is closed with links to the
|
||||
delivery evidence. The separate Sensitive Data Policy issue is created as non-blocking follow-up,
|
||||
linked to #4, and labeled `enhancement` plus `ready-for-human` because its design requires a future
|
||||
`grill-with-docs` before agent implementation.
|
||||
@@ -1,248 +0,0 @@
|
||||
# Installation Model Catalog
|
||||
|
||||
Status: implemented on 2026-09-02.
|
||||
|
||||
## Outcome
|
||||
|
||||
`thothii-installation.yaml` is the only operator-authored source for models used by interactive
|
||||
sessions, metadata generation, and embedding. Runtime-specific files are deterministic projections,
|
||||
not additional configuration sources. Workspace descriptors contain database and Evidence concerns
|
||||
and no model, provider, allowlist, default, embedding, or vector-store configuration.
|
||||
|
||||
This design does not merge execution lifecycles. Pi continues to run interactive sessions, the
|
||||
short-lived LiteLLM helper continues to perform metadata generation, and the internal Ollama service
|
||||
continues to provide embeddings. They share model declaration, not execution machinery.
|
||||
|
||||
## Canonical installation shape
|
||||
|
||||
The following example covers all currently required cases: a Pi built-in model, an authenticated
|
||||
custom endpoint, a keyless internal endpoint, metadata generation, and the single embedding model.
|
||||
|
||||
```yaml
|
||||
schemaVersion: 2
|
||||
profile: server
|
||||
projectDirectory: /srv/thothii
|
||||
envFile: /srv/thothii/operator.env
|
||||
|
||||
workspaceRepository:
|
||||
remote: git@git.example.com:organization/workspaces.git
|
||||
branch: main
|
||||
access: ssh
|
||||
|
||||
modelCatalog:
|
||||
defaults:
|
||||
session: zai/glm-5.3
|
||||
metadataGeneration: local-qwen/qwen3.6-35b-a3b
|
||||
|
||||
embedding:
|
||||
id: ollama/qwen3-embedding:0.6b
|
||||
dimensions: 1024
|
||||
|
||||
providers:
|
||||
deepseek:
|
||||
authentication:
|
||||
mode: pi_auth
|
||||
session:
|
||||
mode: pi_builtin
|
||||
models:
|
||||
deepseek-v4-pro:
|
||||
session: {}
|
||||
deepseek-v4-flash:
|
||||
session: {}
|
||||
|
||||
zai:
|
||||
endpoint:
|
||||
baseUrl: https://api.z.ai/api/coding/paas/v4
|
||||
authentication:
|
||||
mode: secret_env
|
||||
apiKeyEnv: ZAI_API_KEY
|
||||
session:
|
||||
mode: openai_compatible
|
||||
metadataGeneration:
|
||||
litellmProvider: openai
|
||||
models:
|
||||
glm-5.3:
|
||||
label: GLM-5.3
|
||||
session:
|
||||
reasoning: true
|
||||
contextWindow: 200000
|
||||
maxTokens: 131072
|
||||
metadataGeneration: {}
|
||||
|
||||
local-qwen:
|
||||
endpoint:
|
||||
baseUrl: https://ml-aritmolab.policlinicosandonato.it/v1
|
||||
authentication:
|
||||
mode: none
|
||||
session:
|
||||
mode: openai_compatible
|
||||
metadataGeneration:
|
||||
litellmProvider: openai
|
||||
models:
|
||||
qwen3.6-35b-a3b:
|
||||
label: Qwen3.6 35B A3B
|
||||
session:
|
||||
reasoning: false
|
||||
contextWindow: 131072
|
||||
maxTokens: 16384
|
||||
compatibility:
|
||||
supportsDeveloperRole: false
|
||||
supportsReasoningEffort: false
|
||||
supportsStore: false
|
||||
maxTokensField: max_tokens
|
||||
metadataGeneration:
|
||||
disableThinking: true
|
||||
|
||||
authentication:
|
||||
configDirectory: /srv/thothii/auth-canonical
|
||||
runtimeProjection:
|
||||
directory: /srv/thothii/auth-runtime
|
||||
uid: 10001
|
||||
gid: 10001
|
||||
```
|
||||
|
||||
The catalog uses maps instead of repeated IDs. The canonical identity of a model is always derived
|
||||
as `<provider-key>/<model-key>`. `upstreamModel` may be added to a model only when the endpoint uses
|
||||
a different identifier. `label` is optional and falls back to the canonical identity.
|
||||
|
||||
Model eligibility is not repeated in an `usages` array. A `session` block makes the model eligible
|
||||
for sessions; a `metadataGeneration` block makes it eligible for metadata generation. The embedding
|
||||
is a single required installation value rather than a list plus default.
|
||||
|
||||
## Provider and authentication rules
|
||||
|
||||
A provider owns one endpoint, one authentication mode, and zero or one adapter for each runtime.
|
||||
Model entries cannot override provider endpoint or credentials. If the same upstream service needs
|
||||
different endpoints or credentials, the installation declares two provider identities.
|
||||
|
||||
Supported session modes are intentionally closed:
|
||||
|
||||
- `pi_builtin`: Pi already owns the model's technical descriptor; the model's `session` block is
|
||||
empty and ThothII does not copy context-window or compatibility facts.
|
||||
- `openai_compatible`: ThothII generates a Pi custom-provider descriptor; each session model supplies
|
||||
the technical values required by Pi.
|
||||
|
||||
Metadata generation uses the provider-level `litellmProvider`. A model-level
|
||||
`metadataGeneration.disableThinking: true` is permitted only for an explicit compatible endpoint.
|
||||
There is no generic adapter or plugin abstraction in schema version 2.
|
||||
|
||||
Exactly one provider authentication mode is allowed:
|
||||
|
||||
- `secret_env` requires an approved API-key environment reference present in the protected secret
|
||||
bundle. Secret values never enter YAML, generated files, logs, arguments, or API responses.
|
||||
- `pi_auth` is valid only for session-only `pi_builtin` providers and resolves through Pi's protected
|
||||
authentication projection.
|
||||
- `none` is valid only for an explicit endpoint. Runtime projections may supply a fixed non-secret
|
||||
compatibility placeholder when a client library requires a non-empty key.
|
||||
|
||||
## Defaults and selections
|
||||
|
||||
`defaults.session` and `embedding` are required. `defaults.metadataGeneration` is required exactly
|
||||
when at least one model has a `metadataGeneration` block; metadata generation may otherwise be
|
||||
absent and its UI controls are disabled.
|
||||
|
||||
`modelCatalog.defaults.session` is the only configured session-model default. `PI_PROVIDER`,
|
||||
`PI_MODEL`, and provider/model fields in installation-default settings are removed. A user choice is
|
||||
a Model Selection containing only the canonical model identity and runtime controls such as thinking
|
||||
level. A session manifest pins the selected canonical identity.
|
||||
|
||||
Removing the currently selected model causes new-session selection to fall back to the catalog
|
||||
default with an explicit administrative warning. An existing session is never silently moved to a
|
||||
different model; resume fails with `model_unavailable` when its pinned identity can no longer be
|
||||
resolved.
|
||||
|
||||
## Generated runtime projections
|
||||
|
||||
Before Compose starts, `tht` strictly validates schema version 2 and generates installation-local
|
||||
artifacts below `deploy/<installation-id>/generated/`:
|
||||
|
||||
- a normalized catalog JSON consumed defensively by the backend;
|
||||
- Pi `models.json` for custom providers;
|
||||
- Pi `settings.json`, combining fixed product settings with the session-eligible canonical IDs;
|
||||
- a Compose override that mounts the projections and supplies embedding identity and dimensions to
|
||||
core, preprocessing, and `embedding-model-init`.
|
||||
|
||||
Generation is deterministic and published only after every candidate artifact validates. A failed
|
||||
generation aborts start before Compose is invoked. `tht doctor` recomputes expected bytes and reports
|
||||
differences; no digest manifest or separate apply command exists. When projection bytes change,
|
||||
`tht start` recreates the affected services so they cannot continue with an older bind mount.
|
||||
Pi-only restart, update, and rollback operations reject projection drift and direct the operator to
|
||||
`tht start`, because applying only the core-facing files could leave embedding services stale.
|
||||
|
||||
Generated projections are not backed up. Restore validates the canonical installation descriptor,
|
||||
regenerates every projection, and only then starts services. Base Compose files and `operator.env`
|
||||
must contain no model identities, defaults, endpoints, or dimensions.
|
||||
|
||||
## Workspace schema v4
|
||||
|
||||
Workspace schema v4 removes both top-level `llm_policy` and `semantic_index`. The entire latter
|
||||
block is redundant today: its engine and distance are product constants, its collection duplicates
|
||||
the workspace ID, and its model and dimensions are installation facts.
|
||||
|
||||
The runtime derives:
|
||||
|
||||
- Qdrant collection identity from the workspace ID;
|
||||
- engine and distance from the supported product contract;
|
||||
- embedding identity and dimensions from the Installation Model Catalog.
|
||||
|
||||
The published index generation records the canonical embedding identity and dimensions that created
|
||||
it. A mismatch makes the index explicitly incompatible and requires operator-triggered
|
||||
preprocessing. No existing index is deleted or rebuilt automatically.
|
||||
|
||||
The v3-to-v4 workspace migration is deterministic: set `workspace.schema_version` to `4`, remove
|
||||
`llm_policy`, and remove `semantic_index`. It does not alter database, Evidence, diagnostics, or
|
||||
binding data.
|
||||
|
||||
## Installation migration
|
||||
|
||||
Legacy installation migration must inspect all three former sources:
|
||||
|
||||
1. `metadataGeneration` in `thothii-installation.yaml`;
|
||||
2. `deploy/pi/models.json`;
|
||||
3. `deploy/pi/settings.json`.
|
||||
|
||||
The migrator emits a version-2 candidate only when it can reconcile identities, endpoints,
|
||||
credentials, and runtime-specific facts without guessing. Ambiguous aliases such as `glm-53`,
|
||||
`zai/glm-5.3`, and `openai/glm-5.3` are not silently equated. A conflict produces a field-level
|
||||
report and leaves every input unchanged for operator resolution.
|
||||
|
||||
After migration, the strict loader rejects `metadataGeneration`, workspace `llm_policy`, workspace
|
||||
`semantic_index`, legacy Pi source files, unknown fields, duplicate YAML keys, invalid defaults, and
|
||||
incompatible authentication/adapter combinations with an actionable `migration_required` or
|
||||
validation error.
|
||||
|
||||
## Final simplicity audit
|
||||
|
||||
The accepted design removes every configuration duplication that can be removed without inference:
|
||||
|
||||
- one authored installation file instead of an installation block plus two Pi files;
|
||||
- one canonical `provider/model` identity instead of display IDs and runtime IDs;
|
||||
- per-use blocks instead of a duplicated usages list;
|
||||
- one embedding entry instead of a selectable embedding catalog;
|
||||
- one catalog session default instead of environment and settings defaults;
|
||||
- no model or vector-store fields in workspace descriptors;
|
||||
- provider-level credentials instead of per-model credentials;
|
||||
- no generic runtime-plugin abstraction;
|
||||
- no persisted digest, apply command, or backup of generated projections.
|
||||
|
||||
The remaining generated files are necessary boundary adapters, not configuration concepts. Making
|
||||
the backend parse the authoring YAML independently would remove one file but restore two semantic
|
||||
validators. Hard-coding embedding values in Compose would remove one projection but restore a model
|
||||
source outside the catalog. Inferring authentication from missing fields would save one YAML key but
|
||||
turn a safe explicit choice into ambiguity. These apparent simplifications are therefore rejected.
|
||||
|
||||
No further reduction was found that preserves one authority, strict validation, explicit security,
|
||||
session determinism, and model-free workspaces.
|
||||
|
||||
## Implementation surface
|
||||
|
||||
Implementation must update the host `tht` installation loader, setup and lifecycle projection,
|
||||
doctor, backup/restore, Compose mounts and embedding inputs, backend catalog/settings/session model
|
||||
resolution, workspace schema and migration, runtime rendering and diagnostics, frontend workspace
|
||||
drafts and model filtering, examples, fixtures, and documentation. Existing session manifests remain
|
||||
readable and keep their pinned provider/model identity; only resume resolution changes to the new
|
||||
catalog.
|
||||
|
||||
Implementation completed after explicit approval. The installation schema, deterministic runtime
|
||||
projections, migration path, model-free workspace schema v4, backend consumers, operator UI,
|
||||
fixtures, and documentation now enforce this contract.
|
||||
@@ -5,9 +5,9 @@ manuale con commit/push dell'operatore accettati per la release 0;
|
||||
restanti semplificazioni confermate, con chiarimenti su impatto core e controllo Git;
|
||||
E1, E2, E3 e il collegamento ai gate X1 implementati il 2026-09-09.
|
||||
Il contratto X1 è in [Session corrections](../contracts/archive-repair.md). Risultati e limiti in
|
||||
[E1 — validazione](2026-09-09-evidence-e1-validation.md) e
|
||||
[E2 — validazione](2026-09-09-evidence-e2-validation.md) e
|
||||
[E3 — validazione](2026-09-09-evidence-e3-validation.md).
|
||||
[E1 — validazione](../reports/knowledge-archives-release.md) e
|
||||
[E2 — validazione](../reports/knowledge-archives-release.md) e
|
||||
[E3 — validazione](../reports/knowledge-archives-release.md).
|
||||
|
||||
La [revisione di semplicità](2026-09-08-memory-evidence-simplification-review.md)
|
||||
registra il riesame di Q1–Q15. Il flusso principale è draft scritta dallo specialista
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Data del piano: 2026-09-08. Aggiornamento 2026-09-09: M1–M3, E1–E3 e X1
|
||||
implementati. Risultati e limiti della verifica finale sono raccolti nel
|
||||
[rapporto X1](2026-09-09-archive-repair-x1-validation.md).
|
||||
[rapporto X1](../reports/knowledge-archives-release.md).
|
||||
|
||||
La [revisione di semplicità](2026-09-08-memory-evidence-simplification-review.md)
|
||||
riesamina tutte le decisioni Q1–Q15 alla luce degli ultimi chiarimenti del
|
||||
|
||||
@@ -6,7 +6,7 @@ confini di test confermati dal proprietario il 2026-09-08.
|
||||
Primo incremento del progetto Memory management. Attua le decisioni già approvate
|
||||
nel piano del 2026-09-08 e nell'ADR 0018. Le scelte tecniche di dettaglio qui
|
||||
proposte derivano dalla ricognizione del runtime. Gli esiti dell'implementazione
|
||||
sono riportati nel [rapporto di verifica](2026-09-08-memory-m1-validation.md).
|
||||
sono riportati nel [rapporto di verifica](../reports/knowledge-archives-release.md).
|
||||
|
||||
## Problem Statement
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
# M1 — Implementazione e verifica
|
||||
|
||||
Data: 2026-09-08. Implementazione locale della
|
||||
[specifica approvata](2026-09-08-memory-m1-spec.md), associata all'
|
||||
[issue 27](https://git.tylconsulting.it/mptyl/ThothII/issues/27).
|
||||
|
||||
## Risultato
|
||||
|
||||
La pagina **Memory management** è disponibile nell'Administration dopo Database
|
||||
management. Gestisce le quattro famiglie di card, elenco completo, ricerca e filtri,
|
||||
ordinamento, dettaglio, creazione, modifica, cancellazione, collegamenti e dipendenze.
|
||||
Richiede un amministratore autenticato e una selezione esplicita del workspace;
|
||||
non richiede una sessione o un database DWH configurato.
|
||||
|
||||
Il harness possiede l'archivio PostgreSQL `thoth_memory`. Card, collegamenti,
|
||||
dipendenze e lavoro di propagazione sono salvati nella stessa transazione.
|
||||
La pagina distingue salvataggio fallito e contenuto salvato con indice incompleto,
|
||||
offrendo retry anche per le cancellazioni. Recall Memory ed exemplar verificano
|
||||
esistenza, workspace e proiezione corrente nell'archivio prima di restituire contenuto.
|
||||
|
||||
Promozione, salvataggio singolo e finalizzazione corrente passano dal servizio
|
||||
autorevole. Le ricevute della sorgente impediscono duplicati e ricreazione di card
|
||||
cancellate. Reindicizzazione e preprocessing non importano vecchi payload o sessioni.
|
||||
L'errore Memory non annulla una sessione già finalizzata; il gate segnala anche
|
||||
una promozione salvata con indicizzazione incompleta.
|
||||
|
||||
Le migrazioni sono versionate, controllate tramite checksum e incluse nel wheel
|
||||
e nell'immagine core. Il servizio di preparazione `catalog-migrate` le esegue dopo
|
||||
quelle del Catalog. Il runtime assume il ruolo limitato `thoth_memory_runtime`,
|
||||
con isolamento del workspace tramite RLS e senza privilegi DDL.
|
||||
|
||||
## Verifiche eseguite
|
||||
|
||||
| Confine | Esito |
|
||||
| --- | --- |
|
||||
| Harness, test senza L0/L2 | 1.134 passati; i 9 test dei percorsi portabili sono stati eseguiti separatamente e sono passati. |
|
||||
| Servizio Memory, PostgreSQL e Qdrant reali | 17 passati, inclusi CLI, migrazioni, ruolo runtime, isolamento, transazioni, outage, retry, cancellazioni, cambio famiglia e rebuild. |
|
||||
| Gate Pi | 190 passati, inclusi identità UUID e avviso dopo salvataggio con indice incompleto. |
|
||||
| Backend | 1.345 passati nella suite completa, 40 esclusi dalle condizioni previste dai test; un test di autenticazione ha superato il timeout sotto carico. Il relativo file è stato rieseguito isolato: tutti i 17 test passati. |
|
||||
| Frontend | 632 passati, inclusi ingresso dall'AppShell, form, filtri, collegamenti, dipendenze e retry delle cancellazioni. |
|
||||
| Browser integrato | Passato: autenticazione amministratore, creazione, modifica, riavvio del backend, rilettura, cancellazione e assenza nel recall. |
|
||||
| Build e tipi | Build backend e frontend, typecheck TypeScript e build documentale strict superati. |
|
||||
| Lint e diff | Ruff sui file Python modificati e `git diff --check` superati. Il lint globale segnala tre rilievi in file non modificati, elencati sotto. |
|
||||
|
||||
Il browser utilizza autenticamente frontend, login locale, Fastify, ThtRunner,
|
||||
CLI Python, PostgreSQL e Qdrant. Gli embedding sono deterministici e le attività
|
||||
Pi/sessione estranee al percorso Memory usano le fixture esistenti. Non sono state
|
||||
intercettate le API Memory. Sono stati usati container temporanei PostgreSQL 16 e
|
||||
Qdrant 1.18.2, senza accesso a un DWH remoto o a un modello generativo.
|
||||
|
||||
Il test browser ha consentito di correggere etichette accessibili instabili nei
|
||||
campi compilati e la sovrapposizione del pannello di recupero ai comandi del dettaglio.
|
||||
La selezione del workspace e l'uscita dalla pagina sono bloccate durante le operazioni.
|
||||
|
||||
Il lint globale preesistente riguarda soltanto:
|
||||
|
||||
- ordinamento import in `harness/tests/test_effective_relationships.py`;
|
||||
- ordinamento import in `harness/tests/test_p3_dwh_binding.py`;
|
||||
- uso di `datetime.UTC` in `harness/tht/mschema/catalog_snapshot.py`.
|
||||
|
||||
## Riproduzione
|
||||
|
||||
Usare Node 24 e le dipendenze installate dei tre layer. Per eseguire il harness
|
||||
in un ambiente con home non scrivibile si può impostare `THT_HOME` su una directory
|
||||
di prova. I test dei percorsi portabili devono essere eseguiti senza questo override,
|
||||
perché verificano deliberatamente la risoluzione dell'home e di `THT_DATA_ROOT`.
|
||||
|
||||
```sh
|
||||
cd harness
|
||||
THT_HOME=/private/tmp/thothii-m1-test-home .venv/bin/pytest -m 'not l0 and not l2' --ignore=tests/test_portable_paths.py -q
|
||||
.venv/bin/pytest tests/test_portable_paths.py -q
|
||||
.venv/bin/pytest tests/memory/test_administration.py -q
|
||||
npm test
|
||||
```
|
||||
|
||||
```sh
|
||||
cd backend
|
||||
npx vitest run
|
||||
npx tsc --noEmit -p .
|
||||
npm run build
|
||||
```
|
||||
|
||||
```sh
|
||||
cd frontend
|
||||
npx vitest run
|
||||
npx tsc -b
|
||||
npm run build
|
||||
THT_MEMORY_BROWSER_E2E=1 npx playwright test e2e/memory-real.spec.ts
|
||||
```
|
||||
|
||||
Il percorso browser richiede Docker, Python del harness, Go per il bridge di
|
||||
autenticazione e Chromium di Playwright. Avvia risorse isolate e le rimuove alla
|
||||
fine. Su macOS il browser deve poter avviare i processi Chromium fuori dalle
|
||||
restrizioni della sandbox. La build documentale si esegue dalla radice con
|
||||
`./scripts/build-docs.sh`.
|
||||
|
||||
## Stato della consegna
|
||||
|
||||
Le modifiche sono nel worktree locale. Nessuno stack già attivo è stato aggiornato
|
||||
e nessun dato esistente è stato migrato o eliminato. Prima di usare M1 su
|
||||
un'installazione occorrono il nuovo core e la preparazione `catalog-migrate`.
|
||||
M2 (retrieval ibrido ed espansione dei collegamenti), M3 (integrazione estesa nel
|
||||
workflow) ed Evidence management restano incrementi successivi.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Data del piano: 2026-09-08. Aggiornamento 2026-09-09: M1–M3 implementati,
|
||||
con integrazione X1 per le correzioni persistenti dei conflitti. Risultati e limiti
|
||||
sono raccolti nel [rapporto X1](2026-09-09-archive-repair-x1-validation.md).
|
||||
sono raccolti nel [rapporto X1](../reports/knowledge-archives-release.md).
|
||||
|
||||
La [revisione di semplicità](2026-09-08-memory-evidence-simplification-review.md)
|
||||
mantiene il perimetro Memory e precisa un salvataggio sequenziale e una pulizia
|
||||
|
||||
@@ -1,9 +1,31 @@
|
||||
# PRD — Security hardening per Docker personale e server multiutente
|
||||
|
||||
## Ripresa del lavoro e limiti di autorizzazione
|
||||
|
||||
Questo PRD resta una bozza, non una specifica di implementazione approvata. Il precedente
|
||||
prompt di ripresa è stato consolidato qui il 15 settembre 2026. Riconfermare i rilievi
|
||||
SEC-01–SEC-12 contro codice e dipendenze correnti, separando fatti, ipotesi, rischi del
|
||||
profilo locale/server e problemi già risolti. Le vecchie survey non provano lo stato del server.
|
||||
Usare inizialmente controlli in sola lettura e dati sintetici; accesso a server, IdP, DWH
|
||||
o provider e relative mutazioni richiedono target e operazioni concordati.
|
||||
|
||||
Prima di implementare, il proprietario deve confermare profili di fiducia, isolamento
|
||||
del runtime Pi, trattamento dei valori sensibili, revoca, retention, limiti di risorse,
|
||||
priorità e criteri misurabili. I modelli visibili sul server sono un problema separato.
|
||||
Registrare le decisioni in questo PRD; pubblicare spec e ticket Gitea soltanto dopo la
|
||||
conferma del perimetro e della granularità. La bonifica documentale non autorizza il
|
||||
codice di sicurezza, né il rollout di tutti i punti SEC.
|
||||
|
||||
L'implementazione futura richiede un worktree dedicato, test positivi/negativi ai confini
|
||||
concordati, typecheck e revisione contro standard e specifica. Conservare gate manuali,
|
||||
evidenze e rollback; un ticket completato non chiude automaticamente il PRD. Non copiare
|
||||
segreti o dati operativi nei worktree. Usare le skill effettivamente disponibili per
|
||||
chiarimento, diagnosi e revisione, senza assumere che i vecchi nomi dei comandi esistano.
|
||||
|
||||
**Stato:** bozza da validare con `grill-with-docs`; implementazione rinviata.
|
||||
**Data:** 8 settembre 2026.
|
||||
**Owner delle decisioni:** il maintainer di ThothII.
|
||||
**Ripresa:** [prompt per la prossima sessione](2026-09-08-security-hardening-resume-prompt.md).
|
||||
**Ripresa:** seguire la sezione «Ripresa del lavoro e limiti di autorizzazione» sopra.
|
||||
|
||||
Questo documento conserva la survey di sicurezza discussa con il maintainer e propone requisiti,
|
||||
priorità e criteri di accettazione. Non è una spec approvata, un penetration test, una certificazione
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
# Riprendere il PRD di sicurezza con le skill di Pocock
|
||||
|
||||
**Stato:** prompt conservato per uso futuro; nessuna esecuzione programmata.
|
||||
**PRD:** [Security hardening per Docker personale e server multiutente](2026-09-08-security-hardening-prd.md).
|
||||
|
||||
Apri una sessione nella codebase ThothII e incolla il blocco seguente. Il nome corretto della
|
||||
skill è `grill-with-docs`, che combina `grilling` e `domain-modeling`. Il prompt apre la fase di
|
||||
chiarimento; il passaggio a issue, worktree e implementazione resta soggetto alle conferme indicate.
|
||||
|
||||
```text
|
||||
Riprendiamo il lavoro di sicurezza rinviato l'8 settembre 2026.
|
||||
|
||||
Leggi docs/plans/2026-09-08-security-hardening-prd.md. È una bozza di PRD ricavata da una
|
||||
survey storica, non una spec approvata né una prova della configurazione del server remoto.
|
||||
Voglio preparare interventi proporzionati per Docker su Mac/PC personale e per un server
|
||||
multiutente con autenticazione built-in oppure OIDC. Il problema separato dei modelli
|
||||
visibili sul server è fuori perimetro.
|
||||
|
||||
Usa realmente le skill di Matt Pocock: leggi le istruzioni installate, dichiarando quali
|
||||
applichi. Parti da ask-matt per verificare il percorso e da grill-with-docs per il lavoro
|
||||
di design; quest'ultima richiede grilling e domain-modeling. Se una skill non è disponibile,
|
||||
segnalalo e concorda il fallback, senza installarla o fingere di averla eseguita.
|
||||
|
||||
FASE 1 — Riconferma delle evidenze, senza modificare il runtime
|
||||
|
||||
1. Leggi AGENTS.md, PROJECT_STATE.md, CONTEXT.md, le istruzioni docs/agents/ su dominio,
|
||||
issue tracker e label, gli ADR pertinenti e il PRD. Controlla HEAD, stato del worktree
|
||||
e differenze dalla baseline della survey. Preserva tutte le modifiche preesistenti.
|
||||
2. Riconferma i rilievi SEC-01…SEC-12 nel codice corrente. Separa fatti verificati,
|
||||
ipotesi, rischi condizionati al profilo e problemi già risolti. Non trattare i vecchi
|
||||
conteggi delle dipendenze come una scansione aggiornata.
|
||||
3. Usa controlli locali read-only e dati sintetici. Per un difetto da riprodurre, usa
|
||||
diagnosing-bugs con un segnale ripetibile sul comportamento effettivo; una diagnosi
|
||||
non autorizza ancora il fix. Confronta fatti di librerie e advisory con fonti primarie
|
||||
correnti quando necessario, senza inviare codice privato o segreti ai servizi di ricerca.
|
||||
4. Non accedere o intervenire su server, IdP, DWH o provider reali senza aver concordato
|
||||
target e operazioni. Non mostrare API key, cookie, password o campioni di dati reali.
|
||||
|
||||
Esito della fase: una matrice aggiornata che conserva gli ID dei rilievi, con evidenza,
|
||||
profilo interessato e stato. Un fatto ancora non verificabile resta esplicitamente aperto.
|
||||
|
||||
FASE 2 — grill-with-docs, con me presente
|
||||
|
||||
5. Costruisci l'albero delle decisioni. Parti da profili di deploy, fiducia fra utenti e
|
||||
condivisione dei dati; poi affronta isolamento di Pi, policy dei valori sensibili,
|
||||
revoca, retention e limiti seguendo le dipendenze effettive.
|
||||
6. A ogni round presenta soltanto le domande attualmente sbloccate, numerate, con la tua
|
||||
raccomandazione e i trade-off. Attendi le mie risposte prima di assumere le decisioni
|
||||
successive. Cerca autonomamente i fatti ricavabili dal repository; usa agenti di
|
||||
ricerca mirati quando previsto dalla skill, senza delegare a loro le mie decisioni.
|
||||
7. Aggiorna il PRD distinguendo proposte e decisioni confermate. Aggiorna CONTEXT.md solo
|
||||
per termini realmente risolti. Proponi ADR soltanto per scelte difficili da invertire,
|
||||
sorprendenti senza contesto e fondate su alternative reali: basta il formato minimo.
|
||||
8. Concorda requisiti, priorità, rischi accettati e criteri misurabili, inclusi i tempi
|
||||
di revoca e i limiti di risorse. Conferma con me i confini pubblici dei test prima
|
||||
di scriverli. Mantieni espliciti i gate manuali già presenti in PROJECT_STATE.md.
|
||||
|
||||
Esito della fase: nessuna decisione bloccante lasciata implicitamente all'agente;
|
||||
riepilogo e mia conferma della comprensione condivisa. Fino a quella conferma rimani
|
||||
su analisi e documentazione: nessun cambiamento applicativo o di deployment.
|
||||
|
||||
FASE 3 — Spec e ticket, soltanto dopo mia conferma
|
||||
|
||||
9. Usa to-spec per sintetizzare le decisioni già prese, senza riaprire arbitrariamente
|
||||
l'intervista. Chiedimi conferma della pubblicazione prima di creare la spec nel
|
||||
tracker canonico Gitea indicato in docs/agents/issue-tracker.md, non nel mirror GitHub.
|
||||
Collega la spec canonica dal PRD e rendi chiaro quale documento è la fonte aggiornata.
|
||||
10. Usa to-tickets per proporre fette verticali verificabili autonomamente, dimensionate
|
||||
per un contesto fresco. Collega ogni ticket ai requisiti e ai rilievi pertinenti,
|
||||
indica i veri blocker e includi criteri positivi e negativi. Fai approvare granularità
|
||||
e dipendenze prima di pubblicare. Solo i ticket approvati e completi ricevono
|
||||
ready-for-agent; non rimetterli in triage e non chiudere automaticamente la spec padre.
|
||||
11. Se una decisione richiede una prova eseguibile, proponi un prototype limitato a quella
|
||||
domanda prima di fissare la spec. Usa wayfinder solo se il lavoro risulta realmente
|
||||
troppo ampio e incerto per essere chiarito con grill-with-docs.
|
||||
|
||||
Esito della fase: spec approvata e ticket autosufficienti con dipendenze risolte o esplicite.
|
||||
Chiedimi se autorizzo il primo ticket: l'approvazione del design non avvia da sola il codice.
|
||||
|
||||
FASE 4 — Implementazione futura autorizzata
|
||||
|
||||
12. Prima di modificare codice, concorda e crea un worktree dedicato, verificando percorso,
|
||||
branch e commit base. Non riusare una directory occupata, non alterare il worktree
|
||||
originario e non copiare automaticamente segreti o dati operativi. Assicurati che
|
||||
PRD e prompt siano disponibili nel worktree attraverso un passaggio esplicito.
|
||||
13. Esegui implement su un ticket sbloccato per volta, in un contesto fresco. Segui tdd
|
||||
ai confini concordati: un test rosso sul comportamento, implementazione minima,
|
||||
test verde. Esegui typecheck e test mirati durante il lavoro e le suite pertinenti
|
||||
al termine; usa fixture locali per IdP, DWH e provider.
|
||||
14. Esegui code-review sui due assi Standards e Spec, usando i due agenti previsti dalla
|
||||
skill e una base Git fissata. Assicurati che il diff esaminato includa tutto il lavoro
|
||||
del ticket, anche se ancora non committato; un diff vuoto non è una review superata.
|
||||
Risolvi i rilievi e verifica di nuovo. Commit soltanto del lavoro pertinente nel
|
||||
worktree autorizzato; push, merge e deploy richiedono un'autorizzazione distinta.
|
||||
15. Consegna evidenze dei test, istruzioni di adozione e rollback, gate manuali pendenti
|
||||
e rischi residui. Non dichiarare chiuso il PRD intero se è concluso soltanto un ticket
|
||||
o se resta un'accettazione dell'owner.
|
||||
|
||||
Inizia dalla Fase 1, poi proponimi il primo round di grill-with-docs.
|
||||
```
|
||||
@@ -1,112 +0,0 @@
|
||||
# X1 — validation of session archive corrections
|
||||
|
||||
Date: 2026-09-09. The joint Memory/Evidence repair increment is implemented.
|
||||
The authoritative contract is [Session archive corrections](../contracts/archive-repair.md).
|
||||
|
||||
## Delivered behavior
|
||||
|
||||
The session gate shows complete before/after content for specific alternatives targeting
|
||||
Memory or Evidence. The reviewer chooses one correction or rejects all proposals as
|
||||
inadequate and requests reformulation. The resulting receipt survives interruption;
|
||||
saved content and index activation are reported separately. Pending activation offers
|
||||
retry of the same chosen operation. A subsequent curator change blocks replay.
|
||||
|
||||
Application requires an administrator in the harness and the responding browser
|
||||
principal's archive-management permission. Cross-principal runtime responses cannot
|
||||
misattribute the correction. A non-administrator can decline or continue the current
|
||||
question without modifying shared archives. The gate does not advance a workflow phase.
|
||||
|
||||
Memory and Evidence remain separate domains. The integration coordinator reuses their
|
||||
canonical persistence and activation operations. A session Evidence correction requires
|
||||
a consolidated archive, preserves source lineage, and cannot publish unrelated external
|
||||
edits. Existing administration, source import, dependency cleanup and final Memory review
|
||||
remain available. No automatic Git commit or push was added.
|
||||
|
||||
## Verification
|
||||
|
||||
- Harness regression: **1,264 passed**, one skipped, five deselected. All **nine**
|
||||
portable-path checks passed separately without `THT_HOME`. Python lint passed on changed modules.
|
||||
- Backend: **1,366 passed**, 40 skipped. Tests include actual session-response routes
|
||||
for both target archives, unauthorized response, malformed choice and runtime ownership.
|
||||
- Frontend: complete suite **645 passed**; the final display adjustment passed all four
|
||||
focused widget tests. Backend and frontend TypeScript checks passed.
|
||||
- Pi extension: **199 passed**, including closed human choices, rejection, failure/retry,
|
||||
forged selections and the updated public tool schema. The modular skill projection is
|
||||
byte-identical to its updated approved template.
|
||||
- PostgreSQL/Qdrant integration traverses the actual Python CLI for preparation,
|
||||
application and recovery inspection. Corrected Memory and Evidence are retrieved from
|
||||
real indexes, and Evidence activation preserves the Memory card. Session loading is a
|
||||
controlled fixture and embeddings are deterministic; this is not an LLM quality test.
|
||||
- Failure tests cover both targets, index outage, replay, later edits, workspace/session
|
||||
isolation, changed session context, rejection, non-admin writes, and interruption after
|
||||
the Evidence file write but before its saved receipt.
|
||||
- Playwright desktop/mobile: **one passed**. The real widget renders both alternatives,
|
||||
accepts an Evidence choice, displays pending activation and allows retry to active.
|
||||
No page errors or mobile horizontal overflow. Screenshots are
|
||||
`/private/tmp/thothii-x1-repair-desktop.png` and `/private/tmp/thothii-x1-repair-mobile.png`.
|
||||
This browser fixture controls operation outcomes; persistent behavior is tested above.
|
||||
- Strict MkDocs build and `git diff --check` passed.
|
||||
|
||||
## Local installation and reviewer acceptance
|
||||
|
||||
Core and frontend images were rebuilt from this worktree using the existing local
|
||||
preview launcher. Migration `004_archive_repairs.sql` was applied to the existing
|
||||
installation catalog. The new gate is available to session workflows; it is not an
|
||||
always-visible administration panel. Existing PSD archive content was not changed by
|
||||
the synthetic validation cases.
|
||||
All five local services are healthy at `http://127.0.0.1:8080/`.
|
||||
|
||||
The technical increments and their planned checks are complete. The end-user acceptance
|
||||
check remains a real session containing a meaningful domain conflict, with the reviewer
|
||||
evaluating the proposed correction. Automated browser validation uses temporary accounts
|
||||
and data, not the user's authenticated PSD session. Source import retains its E3
|
||||
validation boundaries; no broader model-quality benchmark was added.
|
||||
|
||||
## Follow-up acceptance: configured model
|
||||
|
||||
The opt-in `test_real_model_proposes_a_reviewable_persistent_archive_correction`
|
||||
passed with the installation's **zai/glm-5.3** model. Synthetic Memory asserted an
|
||||
order-ID-only join; synthetic Evidence required the financial year too. The model
|
||||
returned two schema-valid, specific alternatives with complete content and the exact
|
||||
target revisions. The test reviewer selected Memory, persisted the correction through
|
||||
the real coordinator and PostgreSQL, and retrieved the updated rule. Evidence stayed
|
||||
unchanged. This test uses deterministic vectors and the configured completion helper;
|
||||
it does not claim a full autonomous Pi session or human acceptance of PSD semantics.
|
||||
|
||||
The run log is `/private/tmp/x1-acceptance-model.log`. Reproduce with
|
||||
`THT_MEMORY_L2_INSTALLATION=<installation.yaml>` and `THT_MEMORY_L2_CORE=<core-container>`
|
||||
using `pytest -q -s -m l2 tests/memory/test_administration.py -k real_model_proposes`.
|
||||
Credentials are resolved inside core and are not returned to the test runner.
|
||||
|
||||
## Follow-up acceptance: both administration pages
|
||||
|
||||
The opt-in `frontend/e2e/memory-real.spec.ts` passed through real authentication,
|
||||
Fastify, ThtRunner, Python, isolated PostgreSQL and Qdrant. It verifies:
|
||||
|
||||
- Database management, Memory management and Evidence management appear as peers in
|
||||
that order, with no active core session or DWH binding required.
|
||||
- Memory creation, editing, persistence across backend restart, deletion and absence
|
||||
from subsequent recall.
|
||||
- Canonical Evidence remains intact after the Memory deletion. Its full rule is read
|
||||
through the real Evidence administration worker; content filtering finds it and an
|
||||
unmatched filter produces the empty state.
|
||||
- Requests for an unregistered workspace return 404 for both archives.
|
||||
- Desktop and mobile Evidence views render without horizontal document overflow.
|
||||
On phones, both archive pages have at least 380px of usable width at a 390px viewport.
|
||||
Navigation opens in the shared accessible dialog, closes with Escape or archive selection,
|
||||
and returns focus to the trigger after Escape.
|
||||
|
||||
The temporary PostgreSQL readiness probe now waits for TCP, avoiding the image's
|
||||
socket-only initialization server. The browser waits for Memory refresh to finish
|
||||
before leaving its page, matching the existing navigation guard. Visual inspection
|
||||
also exposed a real mobile layout issue: the fixed sidebar left only 134px for the
|
||||
Evidence page. `ArchiveNavigation` now moves that sidebar into the shared dialog below
|
||||
768px on Memory/Evidence pages. Desktop behavior is unchanged. The frontend image
|
||||
was rebuilt for the local preview.
|
||||
|
||||
Run log: `/private/tmp/x1-acceptance-browser7.log` (**one passed**).
|
||||
Screenshots: `/private/tmp/thothii-acceptance-evidence-desktop.png` and
|
||||
`/private/tmp/thothii-acceptance-evidence-mobile.png`. Reproduce with
|
||||
`THT_MEMORY_BROWSER_E2E=1 npx playwright test e2e/memory-real.spec.ts` from `frontend/`.
|
||||
The fixture removes its temporary containers, accounts and checkout on completion.
|
||||
The TypeScript check, Python lint, strict documentation build and diff check also pass.
|
||||
@@ -1,67 +0,0 @@
|
||||
# Evidence E1 — validation
|
||||
|
||||
Date: 2026-09-09. Scope: editable Curated Evidence v4 and the persistent local archive.
|
||||
|
||||
## Implemented behavior
|
||||
|
||||
- Parser, renderer, authoring output and normalization share the existing typed payloads.
|
||||
Visible Markdown edits determine content for all eight kinds. Legacy v1–v3 conversion
|
||||
is explicit and lossless, with errors for content that cannot be represented exactly.
|
||||
- Manual declarations record the curator. A correction preserves the original document
|
||||
as lineage, separately from the current declaration. No source hash is needed to
|
||||
create a manual file.
|
||||
- The local archive records baselines, immutable candidates, active revisions and
|
||||
deletion/source suppression metadata. Unresolved review items and invalid edits block
|
||||
consolidation. Missing archive directories are availability failures, not deletions.
|
||||
- Activation failures preserve the previous active revision. Interrupted normalization
|
||||
replays only unchanged input bytes; later operator edits survive recovery.
|
||||
- Revision-checked correction methods reject stale workflow updates. Legacy preparation
|
||||
and resolution cannot overwrite an initialized local archive; explicit import/refresh
|
||||
integration is deferred to E3.
|
||||
|
||||
## Verification
|
||||
|
||||
The final harness suite excluding opt-in L0/L2 and portable-layout cases passed with
|
||||
**1,180 tests** (58 deselected). All **9 portable-layout tests** passed separately with
|
||||
`THT_HOME` unset. The dedicated real-Qdrant integration test passed, including the
|
||||
optional 35-unit PSD probe. Ruff passed on the changed Evidence implementation and
|
||||
tests, and the strict documentation build succeeded. No frontend or backend TypeScript
|
||||
changes are part of E1.
|
||||
|
||||
The integration test uses an isolated Qdrant 1.18.2 container, the actual corpus
|
||||
pipeline, semantic chunking, vector adapter and active Evidence searcher. Deterministic
|
||||
three-dimensional embeddings isolate file/content correctness from model behavior.
|
||||
It verifies that raw edits do not change recall, consolidation updates recalled content
|
||||
and curator identity, a blocked candidate preserves prior recall, and deletions remove
|
||||
recall. Existing schema and Memory records survive each operation.
|
||||
|
||||
All **35 PSD units** were copied from the owner's workspace into
|
||||
`/private/tmp/thothii-e1-psd.bsW4cp`. Deterministic conversion preserved every ID, payload,
|
||||
scope, provenance and review item. There were no unresolved review items. The optional
|
||||
integration probe then indexed all 35 converted units and compared their complete ID
|
||||
set to the original. It uses PSD's actual `max_chunk_chars: 5000`; a preliminary probe
|
||||
at 4000 correctly blocked an oversized atomic unit.
|
||||
|
||||
Reproduce the isolated real-corpus probe after creating a converted workspace copy:
|
||||
|
||||
```sh
|
||||
cd harness
|
||||
THT_E1_PSD_COPY=/absolute/path/to/converted-copy \
|
||||
.venv/bin/pytest -q -s tests/test_evidence_editable_integration.py
|
||||
```
|
||||
|
||||
The environment variable is optional. Ordinary CI uses only synthetic Evidence. No
|
||||
source refresh, external document download, DWH call or model request is involved.
|
||||
|
||||
## Delivery boundary
|
||||
|
||||
E1 is a core/library increment. E2 must add the installed manual consolidation command,
|
||||
connect runtime source selection to the active local snapshot, and build administrative
|
||||
list/filter/detail with real persistent host paths and manual Git instructions. E3
|
||||
adds source acquisition and explicit refresh/conflict handling. X1 later wires deliberate
|
||||
joint Memory/Evidence corrections into review gates.
|
||||
|
||||
The actual PSD Evidence checkout was not converted. The live Docker preview at
|
||||
`http://127.0.0.1:8080` remains the previously deployed M3 stack, with no new Evidence
|
||||
administration page. The corpus conversion and reindexing described here used copies
|
||||
and disposable test resources.
|
||||
@@ -1,86 +0,0 @@
|
||||
# Evidence E2 — validation
|
||||
|
||||
Date: 2026-09-09. E2 is implemented locally and installed on the existing Docker preview.
|
||||
E3 source imports/refresh and X1 deliberate Memory/Evidence workflow corrections remain open.
|
||||
|
||||
## Delivered behavior
|
||||
|
||||
- Independent **Administration → Evidence management**, after Memory, protected by
|
||||
`evidence.manage`: complete typed content, provenance and original excerpts, review items,
|
||||
pagination, search, kind/purpose/status and scope/source filters, sort, and refresh.
|
||||
- Working-file states distinguish active, modified, new, removed, invalid, legacy and review
|
||||
required. Detail shows the actual configured host path with copy controls. Instructions
|
||||
cover external editing, all eight Markdown templates, consolidation and manual Git.
|
||||
- Installed `tht workspace evidence consolidate --workspace <id> [--json]` uses a closed
|
||||
maintenance envelope. First use converts legacy units. Validation, immutable candidates,
|
||||
activation and retry run through the existing corpus pipeline without a DWH scan or Git.
|
||||
- Runtime and ordinary preprocessing consume the active local snapshot. Unconsolidated
|
||||
edits remain excluded. Catalog/Schema readiness is not advanced by this operation.
|
||||
Clear preserves curated files, archive metadata and Memory; full preprocessing must
|
||||
recreate the missing Reference/Schema derivations afterward.
|
||||
- Immutable runtime lease filenames now identify rendered bytes as well as logical input
|
||||
identity. This fixes upgrades colliding with old runtime files without changing Catalog
|
||||
fingerprints or removing the checks against tampered files.
|
||||
|
||||
## Automated checks
|
||||
|
||||
The complete backend suite passed: **1,355 tests**, 40 skipped. The complete frontend
|
||||
suite passed: **639 tests**. Both TypeScript checks passed. Native Go workspace operation
|
||||
and CLI tests passed, including rejection of arbitrary consolidation flags. Ruff passed
|
||||
for changed Python implementation and test files.
|
||||
|
||||
The harness run passed **1,248 tests**, with one skipped and five deselected. Its three
|
||||
portable-path tests failed because that run deliberately set `THT_HOME` to the test
|
||||
runtime; rerunning the portable tests with `THT_HOME` unset passed. The final focused
|
||||
administration/path suite passed all 18 tests, including actionable migration errors and invalid
|
||||
consolidation combinations rejected before cleanup or indexing.
|
||||
|
||||
The real-Qdrant integration test exercised the actual harness consolidation CLI with
|
||||
deterministic embeddings: all 35 PSD units converted and indexed with stable identities;
|
||||
active-only source selection; separate Schema and Memory canaries; Clear and rebuild
|
||||
from the retained snapshot. Unit tests cover validation, saved-but-unindexed failure,
|
||||
retry, browsing/filtering, no automatic Git, and no Catalog mutation from consolidation.
|
||||
|
||||
A temporary Git repository and bare local remote exercise the documented manual sequence:
|
||||
edit, add and remove files, consolidate, inspect, stage the complete Evidence tree,
|
||||
commit, push and clone. The clone retains changed content, additions, deletions, managed
|
||||
metadata and an accessible active snapshot. No remote user repository was pushed.
|
||||
|
||||
## Installed preview
|
||||
|
||||
The existing Compose project is `thothii-18998cca7b0a`, at `http://127.0.0.1:8080`.
|
||||
The persistent editable checkout is:
|
||||
|
||||
```text
|
||||
/Users/mp/projects/ThothII/deploy/psd/evidence-registry/repo/psd-clinical/evidence
|
||||
```
|
||||
|
||||
The original registry checkout was copied from its retained Docker volume. The original
|
||||
author repository was not changed. Core and maintenance share a nested host bind for
|
||||
`repo`; registry state/snapshots and all other existing data volumes were retained.
|
||||
The installation descriptor includes the existing workspace bindings and the new
|
||||
`evidence-host.yaml` override. The previous descriptor and native binary are backed up
|
||||
at `/private/tmp/thothii-installation-before-e2.yaml` and `/private/tmp/tht-before-e2`.
|
||||
|
||||
The real installed command succeeded with **35 documents, 35 chunks, 35 changed, zero
|
||||
removed**, using the configured embedding service and Qdrant. A second run succeeded
|
||||
with **35 unchanged, zero changed**. Reading the actual archive from core returned
|
||||
35 active units and no file errors. All five long-running services are healthy.
|
||||
Only the Evidence stage ran. The strict documentation build and `git diff --check`
|
||||
also passed. The stack launcher is `bash /private/tmp/thothii-memory-preview.sh`; keep its
|
||||
worktree image-build override until this branch is integrated into the main checkout.
|
||||
|
||||
Browser verification reached the local login page. The saved administrator password
|
||||
does not match the current account hash, so the authenticated visual check remains
|
||||
manual. No account or password was modified. React interaction tests cover navigation,
|
||||
detail, host paths, templates, filtering, pending activation and invalid files.
|
||||
|
||||
## Boundaries
|
||||
|
||||
There is no web content editor, watcher, automatic commit/push, or implicit source refresh.
|
||||
The API exposes administration reads and consolidation; the archive's revision-checked
|
||||
save/remove operations remain available for the later explicit workflow corrections.
|
||||
These gates are not claimed as implemented by E2. Initialized local archives retain
|
||||
structural/review checks but bypass the legacy fixed retrieval-evaluation fixture so
|
||||
its old expected IDs cannot veto deliberate deletions. A general retrieval benchmark
|
||||
is outside the agreed scope.
|
||||
@@ -1,100 +0,0 @@
|
||||
# Evidence E3 — validation
|
||||
|
||||
Date: 2026-09-09. Explicit source import/refresh and decisions are implemented. X1,
|
||||
the integration of deliberate Memory/Evidence corrections into workflow gates, remains next.
|
||||
|
||||
## Delivered behavior
|
||||
|
||||
The independent Evidence page now offers **Sources and imports**. An operator copies
|
||||
a specialist's draft into `evidence/incoming/`, then explicitly imports/refreshes.
|
||||
Original local Markdown and configured HTTP/S3 sources use existing read-only adapters.
|
||||
Acquisition retains raw bytes, source identity and versioned normalized documents.
|
||||
The existing Pi authoring refiner prepares typed, editable v4 proposals.
|
||||
|
||||
Unchanged hashes skip refinement. All source acquisitions/refinements must succeed
|
||||
before saving a new set of comparisons. Missing sources are recorded as unavailable,
|
||||
never interpreted as permission to delete. No runtime lookup, ordinary consolidation
|
||||
or preprocessing triggers remote refresh once the local archive is initialized.
|
||||
|
||||
The administrator sees current and proposed units, scope, content, excerpts, review
|
||||
items and explicit retirement IDs. **Keep local Evidence** records the retained wording
|
||||
as a manual declaration with original lineage. **Use proposed Evidence** adopts the
|
||||
proposal and its source version. Both save and activate through the existing archive
|
||||
and corpus pipeline; review items block adoption. Comparisons use optimistic checks
|
||||
on affected file bytes. Interrupted decisions have a durable replay journal and retry
|
||||
without reacquisition, while intervening external edits are preserved and reported.
|
||||
|
||||
Deleted IDs remain reserved. New model-generated identities from sources with curated
|
||||
deletions are also conservatively suppressed; surviving IDs can still receive reviewed
|
||||
updates. Deliberate new knowledge can be authored as a manual file. This mechanical
|
||||
protection does not depend on the model detecting semantic duplication or contradictions.
|
||||
|
||||
Installed commands are `workspace evidence refresh` and `workspace evidence decide`,
|
||||
alongside E2 consolidation. Decision envelopes carry a source identity, comparison
|
||||
revision and keep/replace choice. Extra URLs, arbitrary paths, forged actors and unknown
|
||||
fields are rejected at the public API/CLI boundary. HTTP requests bind the authenticated
|
||||
curator. Source operations do not mutate Catalog readiness or run DWH/schema stages.
|
||||
The Python source worker is internal; the workflow CLI's visible surface is preserved.
|
||||
|
||||
## Checks
|
||||
|
||||
- Complete backend suite: **1,359 passed**, 40 skipped. Complete frontend suite:
|
||||
**641 passed**. Both TypeScript checks passed; native Go CLI/workspace tests passed.
|
||||
- Harness regression run: **1,256 passed**, one skipped and five deselected, with
|
||||
portable-path tests run separately without `THT_HOME`. All **24 focused import,
|
||||
CLI-surface and portable-path checks** passed. These
|
||||
cover import, unchanged refresh, access failure, missing source, manual correction,
|
||||
keep/replace, deletion suppression, stale comparisons, failure/retry and interrupted
|
||||
journal writes. Ruff passed on the changed Python implementation and tests.
|
||||
- The real-Qdrant test traverses the actual harness source CLI with deterministic
|
||||
refinement/embedding boundaries: import is absent from recall before a decision,
|
||||
accepted content becomes searchable, refreshed proposals preserve active manual
|
||||
corrections, replacement removes the former text, deletion remains absent after
|
||||
another refresh, and unrelated Schema/Memory canaries survive.
|
||||
- Source contract fixtures cover controlled HTTP and S3 identities, exact acquired
|
||||
bytes, and acquisition call counts. Existing adapter tests retain transport/egress
|
||||
coverage. The test does not claim to exercise a live S3 account.
|
||||
- React interaction tests verify explicit refresh, comparison content, exact decisions,
|
||||
saved-decision retry and failure feedback. Route tests cover admin authorization,
|
||||
workspace isolation, strict inputs and principal attribution. Service tests verify
|
||||
the trusted config file descriptor and absence of Catalog mutation.
|
||||
|
||||
## Local preview
|
||||
|
||||
Core/frontend were rebuilt for the existing `thothii-18998cca7b0a` stack. Its persistent
|
||||
archive and data volumes are retained. The native `/usr/local/bin/tht` was updated;
|
||||
the previous executable is at `/private/tmp/tht-before-e3`.
|
||||
|
||||
The installed refresh command ran against `psd-clinical` successfully: **35 unchanged
|
||||
sources, zero changed, zero pending comparisons**. All 35 source hashes matched their
|
||||
existing units, so this probe required no refinement and changed no active Evidence.
|
||||
Source registry metadata was saved locally; no Git commit or push was performed.
|
||||
|
||||
A separate synthetic draft was passed to the configured Pi/model inside core. It
|
||||
produced one domain proposal with one review item, which was not activated. The probe
|
||||
exposed a deployment issue: Python wheel modules and Pi skills live in different
|
||||
directories. The refiner now resolves resources through `THT_HARNESS_DIR`, with the
|
||||
source-tree location as its development fallback; a regression test covers this layout.
|
||||
|
||||
The corrected installed worker was then exercised end to end in a temporary workspace
|
||||
inside core, using the real configured Pi/model and a synthetic `incoming/orders.md`.
|
||||
It returned success, one changed source, one comparison and one proposal with a review
|
||||
item. The active snapshot remained absent. The temporary directory was removed on exit;
|
||||
the probe did not open the DWH or activate an index. Strict docs build and
|
||||
`git diff --check` also passed.
|
||||
|
||||
The in-app browser still showed the login page with the prior credential error.
|
||||
Authenticated visual verification remains manual; no credentials were reset or retried.
|
||||
|
||||
## Operational instructions and boundaries
|
||||
|
||||
See [Import drafts and refresh sources](../contracts/curated-evidence-v4.md#import-drafts-and-refresh-sources)
|
||||
for commands, local paths, review, retry and backup/Git requirements. Preserve the
|
||||
complete Evidence tree, including source comparisons, journals and acquired versions.
|
||||
Local activation and transfer to the remote Git repository remain separate operator steps.
|
||||
|
||||
No web content editor, automatic Git, background watcher, new job queue, general
|
||||
retrieval benchmark or automatic source merge was introduced. Review/refinement is
|
||||
sequential and bounded by per-source limits plus 200 documents/100 MiB per refresh.
|
||||
New changed-source decisions and failure scenarios use isolated test data; live PSD
|
||||
curated content was kept unchanged. X1 is not included in this increment.
|
||||
@@ -1,96 +0,0 @@
|
||||
# M2 — Ricerca ibrida e collegamenti
|
||||
|
||||
Data: 2026-09-09. Implementazione locale dell'incremento M2 del
|
||||
[piano Memory approvato](2026-09-08-memory-management.md#piano-esecutivo).
|
||||
|
||||
## Risultato
|
||||
|
||||
La ricerca Memory ed exemplar usa embedding dense e BM25 in Qdrant. I filtri sono
|
||||
applicati in entrambi i rami prima della selezione dei candidati. Il core espande
|
||||
i collegamenti uscenti, deduplica, limita cicli e visite, riordina insieme i risultati
|
||||
e restituisce il contenuto corrente verificato in PostgreSQL. Non usa un database
|
||||
a grafo né una chiamata LLM per il riordinamento.
|
||||
|
||||
Il contesto fisico distingue database, schema, tabella e colonna e richiede che
|
||||
corrispondano alla stessa dipendenza strutturata. Le card senza dipendenze valgono
|
||||
per il workspace; un riferimento a un antenato fisico si applica ai suoi discendenti.
|
||||
Ambito descrittivo e concetti possono restringere ulteriormente la ricerca tramite
|
||||
`--filters`. La CLI impedisce di sostituire database/schema del runtime. Il dettaglio
|
||||
dei limiti e della formula di ranking è nel [contratto operativo](../gestione-memory.md#hybrid-recall-and-links).
|
||||
|
||||
L'incremento conserva i confini dei gate correnti: F2 riceve chiarimenti di dominio,
|
||||
gli exemplar restano consultativi. Un collegamento non autorizza a consumare una
|
||||
famiglia diversa o una card fuori ambito. Il riepilogo finale, i nuovi gate e la
|
||||
pulizia delle dipendenze dopo sincronizzazione fisica appartengono a M3.
|
||||
|
||||
## Transizione e recupero
|
||||
|
||||
La migrazione versionata `002_hybrid_projection.sql` aggiunge il formato delle
|
||||
proiezioni. Le card M1 restano autorevoli e consultabili; le loro proiezioni dense
|
||||
risultano pendenti e non possono alimentare il recall. Un retry esplicito o
|
||||
`tht memory index -c <runtime.yaml>` costruisce dense e BM25 dal contenuto corrente.
|
||||
Il formato della proiezione e la revisione della card sono verificati prima dell'uso.
|
||||
|
||||
Il salvataggio può aggiungere il vettore sparse mancante nella sola collezione
|
||||
Memory. Non sostituisce configurazioni incompatibili e non modifica Reference.
|
||||
Il rebuild esplicito ricrea anche una collezione Memory assente; il test elimina
|
||||
la collezione, ricostruisce da PostgreSQL e verifica il ritorno della sola card conservata.
|
||||
Fallimenti lasciano il lavoro di propagazione persistito e recuperabile. Nessuna
|
||||
importazione da JSONL, sessioni storiche o vecchi payload Qdrant.
|
||||
|
||||
## Verifiche
|
||||
|
||||
| Controllo | Esito |
|
||||
| --- | --- |
|
||||
| Suite harness senza L0/L2, escluso il file dei percorsi portabili | 1.152 test passati nell'esecuzione finale. |
|
||||
| Suite mirata Memory, adapter e CLI, con embedding reale | 78 test passati. |
|
||||
| Verifica aggiuntiva del rebuild con collezione assente e adapter | 54 passati; il solo test del modello reale era escluso in questa riesecuzione. |
|
||||
| API Fastify Memory | 13 test passati, compresa propagazione della lingua del workspace. |
|
||||
| Browser amministrativo integrato | Passato: creazione, modifica, riavvio, rilettura, cancellazione e verifica del recall. |
|
||||
| Wheel e casi CLI | 10 test passati; il wheel include entrambe le migrazioni Memory. |
|
||||
| Build e controlli statici | Build/typecheck backend, Ruff sui file Python interessati e build documentale strict passati. |
|
||||
|
||||
- Test deterministici: collegamenti necessari, contenuto corrente, duplicati,
|
||||
cicli, profondità e limiti, card mancanti o pendenti, rifiuti già registrati,
|
||||
famiglie e ambiti esclusi, dipendenze omonime e filtri CLI vincolati al runtime.
|
||||
- Adapter: stesso filtro nei prefetch dense/BM25 per Memory ed exemplar; restano
|
||||
coperti i contratti Evidence esistenti.
|
||||
- PostgreSQL/Qdrant: salvataggio, modifica, cambio famiglia, cancellazione,
|
||||
ricostruzione, riferimento separato, isolamento, RLS, errori, retry e transizione
|
||||
delle proiezioni M1 al formato ibrido.
|
||||
- Recupero effettivo: client Ollama di produzione con il modello configurato
|
||||
`qwen3-embedding:0.6b`, dimensione 1024, e Qdrant dell'immagine fissata in Compose.
|
||||
La domanda sulla chiave commessa fra esercizi recupera la regola attesa e la
|
||||
granularità collegata, escludendo un altro database, un altro ambito e dipendenze
|
||||
che corrispondono soltanto combinando riferimenti distinti. Verifica separatamente
|
||||
dense, BM25 e fusione, poi recall, cancellazione e rebuild.
|
||||
|
||||
Il test effettivo avvia un processo Ollama separato, montando il volume del modello
|
||||
installato in sola lettura. PostgreSQL e Qdrant sono container temporanei dedicati,
|
||||
eliminati a fine test. Non usa ID di risultati predisposti. Il browser amministrativo
|
||||
usa invece embedding deterministici: verifica il collegamento fra UI, autenticazione,
|
||||
Fastify, ThtRunner e persistenza, senza essere una misura di qualità del recupero.
|
||||
|
||||
Non è una valutazione generale della qualità semantica su un corpus di produzione;
|
||||
verifica i casi di recupero richiesti da M2, con il percorso reale configurato.
|
||||
|
||||
## Riproduzione
|
||||
|
||||
Dalla directory `harness`, con Docker disponibile:
|
||||
|
||||
```sh
|
||||
THT_HOME=/private/tmp/thothii-m2-test-home \
|
||||
THT_MEMORY_TEST_OLLAMA_VOLUME=<volume-modelli-installazione> \
|
||||
THT_MEMORY_TEST_MODEL=qwen3-embedding:0.6b \
|
||||
THT_MEMORY_TEST_DIMENSIONS=1024 \
|
||||
.venv/bin/pytest -q tests/memory/test_administration.py \
|
||||
tests/memory/test_retrieval.py tests/memory/test_recall.py \
|
||||
tests/test_qdrant_vector_store.py tests/test_solved_search_cli.py
|
||||
```
|
||||
|
||||
Senza il volume esplicito, il solo test con modello reale viene escluso; gli altri
|
||||
test restano eseguibili. Il volume deve contenere il modello indicato. Le immagini
|
||||
Qdrant e Ollama del test sono lette da `compose.yaml`.
|
||||
|
||||
Consegna locale: non sono stati eseguiti deploy, migrazioni delle installazioni
|
||||
attive o aggiornamenti remoti dell'issue tracker.
|
||||
@@ -1,78 +0,0 @@
|
||||
# Memory M3 — validation
|
||||
|
||||
Implemented on 2026-09-09 in the rapid-harbor worktree.
|
||||
|
||||
## Delivered behavior
|
||||
|
||||
- F8 presents an editable summary of proposed additions, explicit updates and links.
|
||||
Only selected content is saved, including the optional solved-question exemplar.
|
||||
- Proposals reference effective approved decisions. Exact existing content is reused.
|
||||
Concurrent edits invalidate an update; manual identities and origins are preserved.
|
||||
- Selected cards and links commit atomically. Durable receipts recover repeat delivery
|
||||
and the gap before the session review marker. Finalization does not add Memory.
|
||||
- F4/F6/F7 retrieve SQL rules and explained errors for the existing approval gates.
|
||||
Retrieval is consultative and does not write an approval decision.
|
||||
- Successful Catalog physical sync deletes cards with matching removed dependencies.
|
||||
The same Catalog transaction marks pending Memory cleanup. Retry keeps the original
|
||||
removals and does not rescan; deletion receipts and projection tombstones survive restarts.
|
||||
- Migration 003 adds minimal review and physical-cleanup receipts.
|
||||
|
||||
## Executed checks
|
||||
|
||||
| Check | Result |
|
||||
| --- | --- |
|
||||
| Harness deterministic suite, excluding portable-path environment cases | 1,152 passed |
|
||||
| Portable-path suite without the temporary THT_HOME override | 9 passed |
|
||||
| Memory service/retrieval with isolated PostgreSQL and Qdrant | 41 passed, 1 optional real-embedding case skipped, 1 L2 case excluded |
|
||||
| Pi gate suite | 195 passed |
|
||||
| Backend full suite | 1,346 passed; one auth timing test exceeded 5 seconds under concurrent load |
|
||||
| Isolated auth and Catalog route rerun | All 40 passed, including the timed-out case |
|
||||
| Catalog PostgreSQL integration after adding atomic cleanup-marker coverage | All 5 passed |
|
||||
| Frontend full suite | 635 passed |
|
||||
| Chromium summary review, desktop and 390px mobile | Passed; no page errors or horizontal overflow |
|
||||
| Configured real GLM 5.3 generation | Passed on synthetic PostgreSQL data |
|
||||
| Backend/frontend production builds, modified Python lint, strict docs build | Passed |
|
||||
|
||||
The existing local Docker preview was rebuilt from this worktree, migration 003
|
||||
was applied, and core/frontend were recreated with the existing persistent volumes.
|
||||
The preview remains at `http://127.0.0.1:8080`.
|
||||
|
||||
The browser check uses the production widget in an isolated Vite fixture. It edits
|
||||
the rule, declines the exemplar, submits only the selected card and checks responsive
|
||||
layout. Gate tests separately verify request ordering through the production Pi
|
||||
composition root; service and Catalog tests use real PostgreSQL. This is not a claim
|
||||
of an automated complete live Pi conversation.
|
||||
|
||||
The L2 case retrieves an approved SQL rule, excludes a card bound to another database,
|
||||
and asks the configured GLM 5.3 model to generate a query. Order IDs repeat between
|
||||
financial years; the correct composite join returns 120 on the synthetic fixture.
|
||||
The generated SQL is validated and executed in a read-only PostgreSQL transaction.
|
||||
No real DWH rows are sent. Embeddings in this case are deterministic; the real
|
||||
embedding/hybrid retrieval evidence remains documented in M2.
|
||||
|
||||
## Reproduction
|
||||
|
||||
From the harness:
|
||||
|
||||
```sh
|
||||
THT_HOME=/private/tmp/thothii-m1-harness-home .venv/bin/pytest -q -m 'not l0 and not l2' --ignore=tests/test_portable_paths.py
|
||||
.venv/bin/pytest -q tests/test_portable_paths.py
|
||||
THT_HOME=/private/tmp/thothii-m1-harness-home .venv/bin/pytest -q tests/memory/test_administration.py tests/memory/test_retrieval.py -m 'not l2'
|
||||
npm test
|
||||
```
|
||||
|
||||
The optional generation case requires an installation YAML path and its running
|
||||
core container. It resolves the model credential inside core without printing it:
|
||||
|
||||
```sh
|
||||
THT_MEMORY_L2_INSTALLATION=<installation.yaml> THT_MEMORY_L2_CORE=<core-container> \
|
||||
.venv/bin/pytest -q -s -m l2 tests/memory/test_administration.py -k real_model
|
||||
```
|
||||
|
||||
From frontend: `npx playwright test e2e/memory-review.spec.ts`.
|
||||
Screenshots are written to `/private/tmp/thothii-m3-summary-desktop.png` and
|
||||
`/private/tmp/thothii-m3-summary-mobile.png`.
|
||||
|
||||
Evidence authoring and the joint X1 persistent Memory/Evidence conflict repair remain
|
||||
outside M3. This increment does not infer knowledge from unexplained failures or
|
||||
promise general improvements in SQL-generation accuracy.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Piano — Full shell e integrazione con il portale
|
||||
|
||||
Stato: implementazione completata e installata sul Mac; deploy server non eseguito.
|
||||
|
||||
Esiti e limiti del collaudo: [rapporto di verifica](../reports/2026-09-13-full-shell-implementation.md).
|
||||
|
||||
Specifica consolidata: [Full shell, integrazione Omics e interfaccia bilingue](2026-09-13-full-shell-spec.md),
|
||||
pubblicata come [specifica su Gitea](https://git.tylconsulting.it/mptyl/ThothII/issues/32).
|
||||
Ticket approvati: [Full sul Mac](https://git.tylconsulting.it/mptyl/ThothII/issues/33),
|
||||
[Embedded Omics](https://git.tylconsulting.it/mptyl/ThothII/issues/34),
|
||||
[Sessioni bilingui](https://git.tylconsulting.it/mptyl/ThothII/issues/35),
|
||||
[Traduzione completa](https://git.tylconsulting.it/mptyl/ThothII/issues/36),
|
||||
[Consegna verificata](https://git.tylconsulting.it/mptyl/ThothII/issues/37).
|
||||
Le dipendenze sono registrate anche nativamente sul tracker.
|
||||
|
||||
## Obiettivo
|
||||
|
||||
Aggiungere una shell autonoma `full` mantenendo compatibile l'integrazione corrente `embedded`
|
||||
con Omics Portal. La complessità del portale deve restare confinata a un `PortalAdapter`.
|
||||
|
||||
## Regole definitive
|
||||
|
||||
- `embedded` è il default e non renderizza alcun header ThothII.
|
||||
- La configurazione installata su questo Mac imposta `shell.mode: full` e
|
||||
`shell.defaultLocale: en`.
|
||||
- Il deploy server imposta `shell.mode: embedded` e `shell.adapter: omics-portal`.
|
||||
- `full` renderizza header, rail sinistro vuoto di almeno 20 px e logout locale.
|
||||
- Fullscreen è uno stato separato dalla shell: il pulsante entra/esce dalla Fullscreen API e
|
||||
l'icona riflette anche l'uscita con `Esc`.
|
||||
- Full include lingua, tema `light/dark`, fullscreen e nome utente; non include la rotellina
|
||||
amministrativa.
|
||||
- Embedded riceve dal portale solo `locale`, `theme` e `fullscreen`; il server verifica l'accesso.
|
||||
- Login e logout embedded restano responsabilità di Omics Portal.
|
||||
- La lingua UI è separata dalla lingua di interazione fissata nella sessione.
|
||||
|
||||
## Sequenza di implementazione
|
||||
|
||||
### 1. Configurazione e stato shell
|
||||
|
||||
- Aggiungere `shell.mode`, `shell.defaultLocale` e `shell.adapter` al descrittore di
|
||||
installazione, mantenendo `embedded` come default quando `shell` non è presente.
|
||||
- Proiettare nel runtime frontend solo configurazione non segreta.
|
||||
- Centralizzare lo stato shell in un controller; i componenti non devono leggere direttamente
|
||||
il portale.
|
||||
|
||||
### 2. Adapter e bridge Omics
|
||||
|
||||
- Implementare `PortalAdapter` con la sola API `subscribe`.
|
||||
- Implementare `OmicsPortalAdapter` osservando il documento condiviso, secondo il contratto rivisto.
|
||||
- Leggere il locale dal selettore renderizzato da Django, osservare il tema e ascoltare il fullscreen.
|
||||
- Conservare il cambio lingua tramite reload Omics e il percorso server di autenticazione esistente.
|
||||
- Validare snapshot e cleanup; in caso di errore mostrare un messaggio di integrazione in
|
||||
embedded, senza fallback a controlli locali.
|
||||
|
||||
### 3. i18n e lingua del modello
|
||||
|
||||
- Introdurre cataloghi UI estendibili, inizialmente `it` e `en`, con fallback inglese.
|
||||
- Usare il locale corrente per le nuove sessioni.
|
||||
- Persistire nel manifest la lingua di interazione e usarla per domande, spiegazioni e scelte
|
||||
del revisore; una ripresa conserva quella lingua.
|
||||
- Non tradurre SQL, identificatori o contenuti del workspace.
|
||||
|
||||
### 4. Shell full
|
||||
|
||||
- Renderizzare header solo in `full`.
|
||||
- Collegare selettore lingua, tema, fullscreen, nome utente e logout alle funzioni già esistenti
|
||||
o equivalenti del frontend/backend.
|
||||
- Implementare il cambio icona e la sincronizzazione con `fullscreenchange`.
|
||||
- Applicare il rail sinistro vuoto con larghezza base semplice e non inferiore a 20 px.
|
||||
|
||||
### 5. Verifica
|
||||
|
||||
- Unit test per validazione adapter, cambio stato, fallback locale e regole di sessione.
|
||||
- Test frontend per entrambe le shell, logout full e fullscreen con `Esc`.
|
||||
- Test backend per il passaggio della lingua nelle nuove sessioni e la conservazione in resume.
|
||||
- Test di integrazione Omics per preferenze iniziali, tema, fullscreen, locale dopo reload e accesso.
|
||||
- Build frontend/backend, suite harness e build documentale.
|
||||
|
||||
## Fuori ambito
|
||||
|
||||
- Cambiare il proxy/authentication chain già operativo.
|
||||
- Passare a iframe o introdurre `postMessage`.
|
||||
- Trasferire token o oggetti utente nel browser bridge.
|
||||
- Aggiungere una shell `system` per il tema o un terzo tema.
|
||||
- Implementare un adapter per un secondo portale: deve solo essere possibile sostituire quello
|
||||
Omics tramite la stessa interfaccia.
|
||||
|
||||
## Gate di approvazione
|
||||
|
||||
L'implementazione è approvabile quando il codice rispetta il [contratto v1](../contracts/portal-shell-adapter-v1.md),
|
||||
la modalità embedded non mostra header proprio e la modalità full non dipende da Omics Portal.
|
||||
@@ -0,0 +1,99 @@
|
||||
# Full shell, integrazione Omics e interfaccia bilingue
|
||||
|
||||
## Problem Statement
|
||||
|
||||
ThothII è utilizzabile nel contenitore di Omics Portal, ma quando viene avviato
|
||||
autonomamente deve offrire i comandi generali che oggi appartengono al portale.
|
||||
Gli utenti devono poter scegliere italiano o inglese per l'interfaccia e per le
|
||||
nuove conversazioni con il modello, senza modificare la lingua dei contenuti del
|
||||
workspace. L'integrazione server deve conservare l'accesso già effettuato in Omics.
|
||||
|
||||
## Solution
|
||||
|
||||
Due modalità di installazione: Full Thoth Shell con header autonomo e Embedded
|
||||
Thoth Shell pilotata dall'header del portale. Sul Mac si installa full con inglese
|
||||
predefinito. Un Portal Shell Adapter sostituibile concentra le conoscenze Omics;
|
||||
l'autenticazione utilizza i percorsi già esistenti. La lingua di interazione
|
||||
rimane fissata per tutta la durata di una sessione, comprese le riprese.
|
||||
|
||||
## User Stories
|
||||
|
||||
1. As an operatore, I want scegliere full o embedded durante l'installazione, so that il contenitore corrisponda al luogo di utilizzo.
|
||||
2. As an operatore Mac, I want full con inglese predefinito, so that l'applicazione sia autonoma appena aperta.
|
||||
3. As an operatore di un'installazione precedente, I want mantenere embedded senza aggiungere configurazioni obbligatorie, so that un aggiornamento non interrompa l'integrazione Omics.
|
||||
4. As an utente full, I want un header con lingua, tema, fullscreen e nome utente, so that i comandi generali siano sempre raggiungibili.
|
||||
5. As an utente full, I want una fascia sinistra vuota di almeno 20 px bilanciata con lo spazio destro, so that il contenuto abbia margini coerenti.
|
||||
6. As an utente full, I want nessuna rotellina amministrativa del portale, so that il contenitore mostri solo i comandi richiesti.
|
||||
7. As an utente full, I want aprire il logout dal nome utente, so that possa terminare il mio accesso.
|
||||
8. As an utente locale, I want usare le credenziali ThothII esistenti, so that non debba configurare Omics.
|
||||
9. As an utente full con OIDC, I want terminare la sessione ThothII, so that il logout non sia limitato al login locale.
|
||||
10. As an utente Omics, I want aprire Datamart Builder già autenticato, so that non debba effettuare un secondo accesso.
|
||||
11. As an utente embedded, I want un solo header fornito da Omics, so that non compaiano comandi duplicati.
|
||||
12. As an utente embedded, I want che login e logout siano gestiti dal portale, so that l'accesso sia coerente con le altre pagine.
|
||||
13. As an utente embedded, I want che ThothII recepisca le preferenze già impostate prima dell'apertura, so that lingua e tema siano subito corretti.
|
||||
14. As an utente, I want scegliere light o dark, so that la leggibilità corrisponda alle condizioni ambientali.
|
||||
15. As an utente, I want leggere form, menu, errori e finestre anche in dark, so that il tema sia completo.
|
||||
16. As an utente full, I want entrare in fullscreen del browser, so that il browser lasci spazio all'applicazione.
|
||||
17. As an utente, I want vedere l'icona di uscita quando il fullscreen è attivo e l'icona iniziale dopo Esc, so that il comando rappresenti lo stato effettivo.
|
||||
18. As an utente, I want un messaggio comprensibile se il browser rifiuta il fullscreen, so that il controllo non mostri uno stato inesistente.
|
||||
19. As an utente, I want tutte le label e i testi non generati dal modello in italiano o inglese, so that possa usare l'applicazione nella lingua scelta.
|
||||
20. As an utente assistito da lettore di schermo, I want nomi accessibili e messaggi tradotti, so that i controlli siano utilizzabili quanto quelli visivi.
|
||||
21. As an utente embedded, I want il cambio lingua segua il normale ricaricamento Omics, so that tutta la pagina condivida la lingua.
|
||||
22. As an revisore, I want ritrovare la sessione dopo quel ricaricamento e proteggere le modifiche non salvate, so that non perda il lavoro.
|
||||
23. As an revisore, I want le nuove domande e scelte del modello nella lingua UI selezionata, so that l'interazione sia comprensibile.
|
||||
24. As an revisore, I want riprendere una sessione nella sua lingua originale, so that le preferenze del nuovo browser non cambino il workflow.
|
||||
25. As an revisore di sessioni precedenti, I want una regola stabile per i manifest privi della lingua di interazione, so that le riprese restino prevedibili.
|
||||
26. As an responsabile dei dati, I want conservare lingua e contenuto di workspace, SQL, identificatori e valori, so that una preferenza UI non alteri i dati.
|
||||
27. As an manutentore, I want aggiungere cataloghi per altre lingue con fallback inglese, so that l'i18n sia estendibile.
|
||||
28. As an integratore, I want sostituire OmicsPortalAdapter con un altro adapter della stessa interfaccia, so that un nuovo portale non richieda modifiche alle pagine o al workflow.
|
||||
29. As an utente il cui accesso scade, I want che lo stato protetto venga chiuso e il rientro segua il contenitore, so that non compaia un login ThothII in embedded.
|
||||
30. As an operatore, I want documentazione accurata di configurazione, autenticazione, adapter, migrazione e verifiche, so that il deploy server sia ripetibile.
|
||||
|
||||
## Implementation Decisions
|
||||
|
||||
- La configurazione installata distingue topologia, autenticazione e shell. Shell omessa significa embedded con adapter Omics predefinito; adapter sconosciuti sono errori espliciti. Full non istanzia adapter.
|
||||
- La configurazione frontend pubblica contiene soltanto dati non segreti e usa il meccanismo runtime esistente, compreso il prefisso API necessario al montaggio Omics.
|
||||
- Un controller di shell espone preferenze e stato; i componenti non accedono direttamente al portale.
|
||||
- L'interfaccia PortalAdapter offre una sottoscrizione con snapshot iniziale, aggiornamenti, errori e disiscrizione. Lo snapshot contiene locale, tema light/dark e fullscreen.
|
||||
- L'implementazione Omics legge la lingua effettivamente renderizzata dal selettore, osserva il tema sul documento e ascolta il fullscreen del browser. Non introduce handshake, eventi personalizzati o polling per le preferenze. Il contratto DOM è privato dell'adapter.
|
||||
- Il montaggio resta nello stesso documento. Nessun header o comando locale di autenticazione/presentazione viene introdotto in embedded.
|
||||
- Il server resta autorevole per identità e autorizzazioni. Il bridge UI non trasmette token, utente o flag authenticated. La catena di identità fidata esistente viene conservata.
|
||||
- I rifiuti di accesso all'applicazione devono essere distinti dai 403 relativi a una singola operazione. Ricontrollare l'accesso alla riconnessione e al ritorno alla pagina; non promettere revoca istantanea di altre schede tramite il solo proxy.
|
||||
- Full riutilizza login e logout esistenti, preserva le protezioni dalle modifiche non salvate e abilita il logout anche per sessioni ThothII OIDC. Il logout globale dall'identity provider non è implicito.
|
||||
- Fullscreen è indipendente dalla modalità full. L'icona segue lo stato effettivo e le richieste rifiutate sono gestite. I token dark esistenti vengono completati, con verifica dei contenuti sovrapposti e dell'isolamento degli stili embedded.
|
||||
- L'i18n utilizza cataloghi estendibili EN/IT con fallback inglese, comprese label, aiuti, placeholder, accessibilità, errori e widget deterministici. I payload tecnici restano stabili.
|
||||
- La lingua di interazione viene scelta dal locale UI risolto, salvata nel manifest e propagata al contesto del modello. Resume non accetta override dal browser.
|
||||
- Le sessioni precedenti prive del campo usano la lingua del workspace come compatibilità; il valore viene fissato alla prima ripresa mediante aggiornamento idempotente. Non si pretende di ricostruire una lingua storica non registrata.
|
||||
- Il cambio lingua Omics mantiene la navigazione Django. La selezione della sessione deve sopravvivere alla navigazione; le modifiche non salvate devono essere protette, senza avviare una nuova generazione implicitamente.
|
||||
|
||||
## Testing Decisions
|
||||
|
||||
I punti di verifica erano già approvati nel piano: comportamento della shell e
|
||||
dell'accesso dall'interfaccia, contratto pubblico dell'adapter, creazione/ripresa
|
||||
tramite API e CLI del workflow, configurazione d'installazione e integrazione
|
||||
Omics. Non si richiede una nuova approvazione degli stessi punti.
|
||||
|
||||
- Test comportamentali: stato osservabile, testo e controlli accessibili, permessi e lingua persistita; evitare metodi privati o asserzioni sull'organizzazione interna.
|
||||
- Riutilizzare i test AuthGate/AppShell con API simulate al confine HTTP, quelli delle route sessioni e quelli pubblici del repository/CLI del workflow.
|
||||
- Verificare adapter con un documento equivalente al template reale, preferenze iniziali, aggiornamenti e cleanup; includere montaggio ripetuto.
|
||||
- Verificare nuova sessione, resume con lingua UI diversa, manifest precedente e input locale invalido; il contesto fornito al modello deve contenere la lingua persistita.
|
||||
- Verificare fullscreen con ingresso, uscita, Esc e rifiuto; entrambe le modalità con dark, form e menu aperti.
|
||||
- Verificare accesso embedded senza secondo login, scadenza/403, riconnessione degli eventi e ritorno a una scheda; verificare logout full e protezione dei dati di un utente precedente.
|
||||
- Typecheck e test mirati durante lo sviluppo; suite complete alla fine, build documentale e prova browser proporzionata. Non usare chiamate reali al modello per i test deterministici.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Deploy sul server di produzione o modifica delle credenziali.
|
||||
- Seconda implementazione per un portale futuro, iframe e protocollo postMessage.
|
||||
- Nuovo sistema di autenticazione, propagazione di token nel browser o logout globale OIDC.
|
||||
- Tema system, ingresso automatico in fullscreen, rotellina amministrativa nell'header full.
|
||||
- Traduzione di SQL, dati, identificatori o contenuti del workspace; traduzione a posteriori delle decisioni generate dal modello.
|
||||
- Persistenza di una trascrizione integrale delle conversazioni.
|
||||
|
||||
## Further Notes
|
||||
|
||||
La revisione della semplificazione del 2026-09-13 è stata approvata dall'utente e
|
||||
prevale sui dettagli superati del primo contratto a eventi. La specifica consolida
|
||||
le decisioni senza riaprire l'intervista. Le modifiche vengono revisionate sui due
|
||||
assi Standards/Spec e committate sul branch corrente, preservando i cambiamenti
|
||||
preesistenti estranei a questa funzionalità.
|
||||
@@ -0,0 +1,99 @@
|
||||
# Piano per l’installazione manuale standalone
|
||||
|
||||
**Stato:** design concordato con grill-with-docs il 2026-09-14. Questo worktree definisce e rende
|
||||
verificabile il percorso manuale; non introduce pacchetti nativi.
|
||||
|
||||
## Obiettivo
|
||||
|
||||
Permettere di predisporre una copia di THothII su macOS, Windows e Linux partendo dal clone del
|
||||
repository Gitea, con una configurazione locale breve e una sequenza di comandi espliciti da
|
||||
terminale.
|
||||
|
||||
“Standalone” indica una Full Thoth Shell con servizi applicativi e semantici locali eseguiti da
|
||||
Docker. DWH e provider LLM restano configurazioni esterne dell’installazione. Non si promette un
|
||||
runtime offline.
|
||||
|
||||
## Decisioni concordate
|
||||
|
||||
| Decisione | Scelta |
|
||||
| --- | --- |
|
||||
| Distribuzione | clone del repository Gitea |
|
||||
| Esperienza di installazione | comandi manuali, senza installer grafico, launcher o wrapper nativo |
|
||||
| Runtime applicativo | Docker Compose del repository |
|
||||
| Bootstrap host | `scripts/install-tht.sh` installa soltanto il comando operatore `tht` |
|
||||
| Configurazione | setup locale interattivo, con percorsi predefiniti e file protetti separati |
|
||||
| Modalità shell | `full`, locale, con `defaultLocale: en` |
|
||||
| Windows | Ubuntu in WSL2 con integrazione Docker Desktop |
|
||||
| Architetture iniziali | macOS Apple Silicon, Windows x64, Linux x64 |
|
||||
| Immagini pre-costruite | Docker Hub in uno step successivo |
|
||||
| Verifica | Gate A di piattaforma su tre host; Gate B funzionale su almeno un host |
|
||||
| Documentazione | due guide sincronizzate, italiano e inglese |
|
||||
|
||||
## Sequenza operativa canonica
|
||||
|
||||
1. Installare Git, Docker Desktop oppure Docker Engine + Compose v2 e Bash.
|
||||
2. Su Windows, predisporre WSL2 Ubuntu e abilitarne l’integrazione in Docker Desktop.
|
||||
3. Clonare `https://git.tylconsulting.it/mptyl/ThothII.git` e annotare la revisione.
|
||||
4. Eseguire `scripts/check-standalone-prerequisites.sh`.
|
||||
5. Eseguire `scripts/install-tht.sh` e verificare `tht version`.
|
||||
6. Preparare le due password catalogo ed eseguire `tht setup --profile local --shell-mode full --shell-default-locale en --configure-only`.
|
||||
7. Completare file protetti, percorsi password in `operator.env` e catalogo modelli; generare le
|
||||
proiezioni, costruire le immagini, avviare `catalog-db`, eseguire `catalog-migrate` e `tht start`
|
||||
sullo stesso progetto Compose (sequenza completa nelle due guide).
|
||||
8. Eseguire `scripts/verify-standalone-install.sh` passando il descriptor generato.
|
||||
9. Registrare separatamente il risultato del Gate A e del Gate B.
|
||||
|
||||
`tht setup` genera `deploy/local/thothii-installation.yaml` e `deploy/local/operator.env`, prepara
|
||||
le proiezioni runtime e valida Compose; `--configure-only` rimanda build e avvio fino al
|
||||
completamento della configurazione e della migrazione. Il file tracciato
|
||||
`deploy/env/local.env.example` resta un riferimento; non è il descriptor attivo della procedura
|
||||
generata.
|
||||
|
||||
## Contratti di sicurezza
|
||||
|
||||
- I segreti non entrano nel clone, nel descriptor YAML, nelle URL, nei log o negli argomenti della
|
||||
shell.
|
||||
- I file in `deploy/local/` sono ignorati da Git e restano sotto il controllo dell’operatore.
|
||||
- Il bundle `thothii.secrets` usa righe `KEY=VALUE` e contiene solo le credenziali richieste dai
|
||||
provider selezionati.
|
||||
- L’accesso Git del workspace usa un file credential protetto oppure una chiave SSH e `known_hosts`;
|
||||
il clone sorgente e il repository workspace restano distinti.
|
||||
- `stop`, `start` e `doctor` sono operazioni di lifecycle; `down --volumes` è distruttivo e non fa
|
||||
parte della prova normale.
|
||||
|
||||
## Matrice di accettazione
|
||||
|
||||
| Gate | Host | Esito richiesto |
|
||||
| --- | --- | --- |
|
||||
| A | macOS Apple Silicon | clone, Docker/Compose, build, setup, doctor e frontend locali OK |
|
||||
| A | Windows 11 x64 + WSL2 | stessi controlli eseguiti dalla shell Ubuntu WSL2 |
|
||||
| A | Ubuntu Linux x64 | stessi controlli con Docker Engine + Compose v2 |
|
||||
| B | almeno uno dei tre host | login, workspace leggibile, domanda reale fino alla SQL finale, stop/start OK |
|
||||
|
||||
Un errore del DWH, del provider LLM, del repository workspace o delle credenziali viene registrato
|
||||
come errore funzionale/configurativo distinto dal risultato di portabilità Docker.
|
||||
|
||||
## Artefatti del worktree
|
||||
|
||||
- `docs/install/standalone-manual-it.md`: procedura italiana utilizzabile durante l’installazione;
|
||||
- `docs/install/standalone-manual-en.md`: versione inglese sincronizzata;
|
||||
- `scripts/check-standalone-prerequisites.sh`: controllo read-only dell’host;
|
||||
- `scripts/verify-standalone-install.sh`: controllo read-only dell’installazione avviata;
|
||||
- aggiornamento di navigazione e contratto documentale;
|
||||
- questo piano come riferimento per il successivo lavoro di packaging.
|
||||
|
||||
## Evoluzioni escluse
|
||||
|
||||
Non fanno parte di questa fase DMG, MSI/EXE, AppImage, wrapper nativi, installazione automatica di
|
||||
Docker, immagini Docker Hub, configurazione non interattiva completa, DWH locale o LLM locale.
|
||||
|
||||
La prossima evoluzione consigliata è pubblicare immagini versionate e ripetere la stessa matrice
|
||||
senza build dal sorgente. Solo dopo una prova riuscita sui tre host sarà opportuno valutare una
|
||||
configurazione ridotta e, separatamente, eventuali pacchetti nativi.
|
||||
|
||||
## Revisione per pubblicazione — 2026-09-15
|
||||
|
||||
Le guide separano configurazione e avvio, includono password e migrazioni Catalog/Memory,
|
||||
richiedono di completare il catalogo modelli e distinguono la verifica del doctor dalle dipendenze
|
||||
esterne. Le directory di autenticazione locali sono escluse da Git. Le prove complete da clone
|
||||
sui tre sistemi restano pendenti; il controllo documentale non le sostituisce.
|
||||
@@ -0,0 +1,43 @@
|
||||
# What ThothII does
|
||||
|
||||
ThothII helps turn a natural-language question into reviewed SQL. It is intended for
|
||||
people who know the meaning of their data and need to make the assumptions behind a
|
||||
query explicit. The model proposes; a human reviewer approves, corrects or rejects.
|
||||
|
||||
## From a question to a reusable result
|
||||
|
||||
The [eight-phase workflow](skills.md) clarifies the question, consults reusable knowledge,
|
||||
selects relevant Evidence and database objects, prepares a query plan, and produces SQL
|
||||
for review. Approved knowledge can be saved for later questions.
|
||||
|
||||
- **Workspace:** the domain context and its Evidence configuration.
|
||||
- **Database catalog:** tables, columns, relationships and reviewed descriptions.
|
||||
- **Evidence:** domain sources and rules with provenance that a reviewer can inspect.
|
||||
- **Memory:** reusable clarifications, SQL rules, solved questions and explained errors.
|
||||
- **Session:** the saved artifacts and decisions for one question, not a permanent chat transcript.
|
||||
|
||||
Resuming a session uses its saved state. Model output is a proposal, not a guarantee of
|
||||
correctness: review the scope, assumptions, sources and SQL before relying on the result.
|
||||
|
||||
## What an installation includes
|
||||
|
||||
The Docker stack includes the web application, its runtime, a PostgreSQL metadata/Memory
|
||||
catalog, Qdrant and the embedding service. A browser is the normal user interface; the
|
||||
host `tht` command is used to configure and operate the installation.
|
||||
|
||||
The data warehouse and generative model endpoints are configured separately. Docker
|
||||
does not supply their credentials, network access or domain data. A standalone installation
|
||||
is therefore self-hosted, but is not automatically offline or independent of those services.
|
||||
Review data-access permissions and the model-provider configuration before using real data.
|
||||
|
||||
## Choose your next step
|
||||
|
||||
- Install on Mac, Windows through WSL2, or Linux: [Italian](install/standalone-manual-it.md)
|
||||
or [English](install/standalone-manual-en.md) manual procedure.
|
||||
- Configure [display mode and language](install/shell-and-language.md),
|
||||
[authentication](install/authentication-local.md) and [models](general/pi-configuration.md).
|
||||
- Prepare [workspaces](operations/workspaces.md) and [databases](operations/database-management.md).
|
||||
- Start a reviewed question using the [user guide](guida-utente.md).
|
||||
|
||||
The installation guides state the platform tests still to complete. Availability of a
|
||||
procedure is not a certification that every target machine has been tested.
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Stato: **pubblicata per revisione visiva, non integrata in main**.
|
||||
|
||||
Aggiornamento 2026-09-13: i sette commit di questa revisione sono ora integrati con
|
||||
full/embedded e i18n nel ramo `codex/prototype-administration-pages`, su richiesta
|
||||
del proprietario. Per lo stato corrente e il rollback usare il
|
||||
[rapporto di integrazione](2026-09-13-visual-shell-integration.md).
|
||||
Il seguito conserva la cronologia della consegna isolata originale.
|
||||
|
||||
## Dove provarla
|
||||
|
||||
- Docker locale: <http://127.0.0.1:8080/>.
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
# Full shell, Omics e interfaccia bilingue — verifica
|
||||
|
||||
Data: 2026-09-13. Specifica: [Full shell, integrazione Omics e interfaccia bilingue](../plans/2026-09-13-full-shell-spec.md).
|
||||
I cinque ticket e le loro dipendenze sono elencati nel [piano](../plans/2026-09-13-full-shell-and-portal-integration.md).
|
||||
|
||||
Correzione della base grafica: la prima build descritta qui non includeva i sette
|
||||
commit del ramo `codex/ui-visual-review` già installati sul Mac. Il
|
||||
[rapporto di integrazione](2026-09-13-visual-shell-integration.md) documenta il
|
||||
recupero di font, allineamenti e layout, mantenendo le funzionalità di questa consegna.
|
||||
|
||||
## Risultato
|
||||
|
||||
- Configurazione pubblica generata dal descrittore installato; full ed embedded
|
||||
usano la stessa immagine frontend. Sul Mac: `full`, locale iniziale `en`.
|
||||
- Header full con lingua, tema, fullscreen reale e menu utente/logout; rail sinistro
|
||||
vuoto di almeno 20 px. Nessuna rotellina amministrativa.
|
||||
- Embedded senza header locale; `OmicsPortalAdapter` incapsula l'osservazione del
|
||||
portale. Identità e autorizzazioni rimangono verificate dal server.
|
||||
- Cataloghi EN/IT, traduzioni dei controlli delle griglie, grafici e SQL adattati
|
||||
al tema. I contenuti di dominio rimangono invariati.
|
||||
- `interaction_language` fissata nel manifest: cattura alla creazione, mantenimento
|
||||
alla ripresa e assegnazione atomica del valore workspace per sessioni precedenti.
|
||||
- Continuità della selezione al reload, nessuna ripresa automatica del modello e
|
||||
protezione delle bozze non inviate.
|
||||
|
||||
La [guida operativa](../operations/shell-and-localization.md) descrive configurazione,
|
||||
accesso, estensione ad altri portali/lingue e checklist di deploy.
|
||||
|
||||
## Verifiche automatiche
|
||||
|
||||
| Livello | Esito |
|
||||
| --- | --- |
|
||||
| CLI nativa Go | `go test ./...`: 21 package verificati |
|
||||
| Harness Python | 1290 passati, 1 saltato, 6 L2 esclusi |
|
||||
| Gate Pi JavaScript | 205 passati |
|
||||
| Frontend | suite completa: 755 passati in 90 file; regressione CSS prebuild superata |
|
||||
| Backend | suite completa Node 24: 1397 passati, 40 saltati |
|
||||
| Omics Docker isolato | 15 test Django/integrazione passati; controlli JavaScript del browser inclusi |
|
||||
| Cataloghi | 1666 messaggi italiani, 1701 riferimenti statici; conflitti e interpolazioni verificati |
|
||||
| Build | frontend, backend/typecheck e documentazione MkDocs strict verificati; regressione CSS eseguita automaticamente prima della build frontend |
|
||||
|
||||
La suite backend richiede Node 24. Sul Mac il percorso Homebrew `node@24`
|
||||
risolveva a Node 25; è stato usato esplicitamente Node 24.16.0 già presente in NVM,
|
||||
senza modificare il runtime globale. Un test preesistente sul timeout di arresto
|
||||
di un processo è fallito sotto carico parallelo ed è passato isolatamente;
|
||||
la verifica finale usa un solo worker.
|
||||
|
||||
I test coprono comportamenti pubblici e confini approvati: manifest filesystem e
|
||||
PostgreSQL, CLI, Fastify, processo Pi simulato, stream SSE, shell e widget React,
|
||||
template/autorizzazione Omics. Non è stata avviata una nuova generazione L2 contro
|
||||
il modello remoto o il DWH operativo. Il controllo statico dei cataloghi non è
|
||||
una prova di traduzione di ogni possibile messaggio diagnostico esterno.
|
||||
|
||||
## Standards
|
||||
|
||||
Revisione indipendente rispetto al punto iniziale ThothII
|
||||
`2d1b714ebe31419d712e9c3324a5e171d5f0317d` e Omics `aff7581`.
|
||||
Due violazioni concrete del contratto: bozze dei gate non protette dal reload e
|
||||
selezione di sessioni altrui persa per gli amministratori. Entrambe corrette e
|
||||
riesaminate dal revisore indipendente. La protezione resta attiva anche durante
|
||||
un invio e dopo un errore HTTP, fino all'accettazione e allo smontaggio del widget.
|
||||
Nessun ulteriore rilievo concreto sul codice Omics o sulle euristiche di manutenibilità.
|
||||
Esito finale del revisore: approvato, zero rilievi aperti.
|
||||
|
||||
## Spec
|
||||
|
||||
Quattro rilievi: i due precedenti, più verifica dell'identità mancante dopo una
|
||||
riconnessione SSE riuscita ed errori deterministici dello stream non tradotti.
|
||||
Le correzioni includono test di regressione e sono state riesaminate dal revisore
|
||||
indipendente. Sono tradotti anche gli errori sanitizzati di avvio e le notifiche
|
||||
deterministiche dei gate già localizzate nella lingua fissata della sessione.
|
||||
Esito finale del revisore: tutti e quattro i rilievi chiusi, nessun nuovo rilievo
|
||||
o ampliamento ingiustificato dell'ambito.
|
||||
|
||||
Riepilogo iniziale: Standards 2 rilievi P2; Spec 4 rilievi P2. Gli assi restano
|
||||
separati; i rilievi comuni non rappresentano ulteriori difetti distinti.
|
||||
Riepilogo finale: Standards 0 aperti; Spec 0 aperti.
|
||||
|
||||
## Collaudo visivo
|
||||
|
||||
Il collaudo con l'account locale autenticato ha trovato tre difetti non visibili
|
||||
nei test DOM dei componenti:
|
||||
|
||||
1. Il contenitore CSS `@scope` includeva l'intero livello base Tailwind e nel browser
|
||||
integrato non applicava i token. Il CSS era servito con HTTP 200, ma il font
|
||||
effettivo era Times e `--background` risultava vuoto. L'isolamento del reset
|
||||
è ora compilato in selettori ordinari, senza modificare gli stili del portale.
|
||||
Il browser applica Manrope e i token light/dark corretti. Revisione indipendente
|
||||
del CSS compilato: nessuna perdita di isolamento individuata.
|
||||
2. La classe full costruita per interpolazione faceva eliminare il token del
|
||||
margine dalla build Tailwind. Nomi di classe letterali e una regressione sulla
|
||||
presenza di `--thot-shell-gutter` rendono il requisito verificabile nella build.
|
||||
3. Le griglie amministrative caricavano il tema CSS preesistente insieme al nuovo
|
||||
tema automatico della libreria. Griglie amministrative e anteprime ora usano
|
||||
un solo sistema CSS con i token della shell, eliminando il conflitto. I token
|
||||
vengono applicati anche ai contenitori di tema interni creati da AG Grid,
|
||||
che altrimenti sovrascriverebbero i colori ereditati.
|
||||
|
||||
Questi controlli sono stati eseguiti prima del commit di consegna. Il nuovo test
|
||||
`scripts/scoped-base.test.mjs` viene eseguito dal comando `prebuild` anche in Docker.
|
||||
Le prove di lingua/tema non hanno modificato dati del catalogo o avviato sessioni.
|
||||
|
||||
## Installazione locale e recupero
|
||||
|
||||
Il binario nativo aggiornato è installato in `/usr/local/bin/tht`.
|
||||
Il descrittore locale, non versionato, è
|
||||
`deploy/psd/thothii-installation.yaml`; `installation generate` ha prodotto:
|
||||
|
||||
```javascript
|
||||
window.__THOTHII_CONFIG__ = {"backendBaseUrl":"/api","shell":{"mode":"full","defaultLocale":"en"}};
|
||||
```
|
||||
|
||||
Il progetto Docker locale è `thothii-18998cca7b0a`; l'aggiornamento riguarda soltanto
|
||||
core/frontend. Database, Qdrant, embedding e volumi persistenti restano invariati.
|
||||
Le immagini precedenti sono conservate come
|
||||
`thothii-core:before-full-shell-20260913` e
|
||||
`thothii-frontend:before-full-shell-20260913`.
|
||||
Binario e descrittore precedenti sono in `/private/tmp/thothii-shell-install.8idNoC`
|
||||
(copia temporanea locale, non backup permanente).
|
||||
|
||||
Il sorgente Omics aggiornato è registrato nel commit locale `95154e1`.
|
||||
Nessun push o deploy sul server di produzione è stato eseguito. Il collaudo
|
||||
operativo sul server resta una fase del normale rilascio, seguendo la guida.
|
||||
|
||||
Core/frontend locali aggiornati e healthy; `/api/health` restituisce 200,
|
||||
`/config.js` espone full/en e `/api/auth/config` conferma l'accesso locale.
|
||||
Con l'account locale autenticato sono stati controllati header, cambio EN/IT,
|
||||
light/dark, menu utente/logout, ingresso/uscita fullscreen tramite pulsante e
|
||||
margini effettivi di 24 px. I test automatici coprono logout e sincronizzazione
|
||||
con `fullscreenchange`, compreso il ritorno allo stato normale. L'uscita tramite
|
||||
tasto Esc nativo resta da provare in un browser desktop ordinario: il comando
|
||||
di tastiera automatizzato del browser integrato non l'ha riprodotta. Nessuna
|
||||
promessa di collaudo completo del browser del server è implicita in queste prove.
|
||||
Le preferenze locali sono state riportate a inglese e tema chiaro.
|
||||
@@ -0,0 +1,105 @@
|
||||
# Ritocchi header e layout
|
||||
|
||||
Data: 13 settembre 2026. Ambito: frontend ThothII e installazione locale del Mac.
|
||||
Nessuna modifica al repository Omics o deploy sul server PSD.
|
||||
|
||||
## Modifiche
|
||||
|
||||
- Header full `#CB333B`, valore di `--gsd-red-primary` in Omics
|
||||
`static/css/gsd-theme.css`. Marchio completo e controlli chiari in entrambi i
|
||||
temi; opzioni lingua, hover, focus ed errori rimangono leggibili. Gli altri
|
||||
marchi conservano il suffisso rosso. Embedded non aggiunge alcun header.
|
||||
- Catalog, Operations e Metadata updated separati di 16px dal divisore superiore.
|
||||
- Due selettori e Done allineati in un'unica riga desktop; controlli alti 32px.
|
||||
Il contenitore stretto impila i controlli. Retry, blocchi operativi e messaggi
|
||||
di errore rimangono disponibili; le scelte mantengono lo stesso comportamento.
|
||||
- Bordo inferiore rimosso dai tab My sessions e All sessions; stato selezionato,
|
||||
focus e navigazione da tastiera conservati.
|
||||
|
||||
Impeccable, registro product, ha guidato il mantenimento della gerarchia esistente
|
||||
e dell'adattamento agli schermi stretti, senza introdurre nuovi componenti.
|
||||
|
||||
## Verifiche
|
||||
|
||||
Typecheck superato; 71 test nelle suite AppShell.host, AppShell.administration e
|
||||
AppShell.session-mgmt; 11 scenari Playwright della revisione visuale superati.
|
||||
Le nuove asserzioni controllano colore header light/dark, colore del suffisso,
|
||||
spazio degli stati, posizione di Done, assenza del bordo e overflow. Verificati
|
||||
gli screenshot desktop/mobile e scuro; le transizioni sono completate prima della
|
||||
cattura. Fixture sintetiche, nessun modello o dato reale modificato dai test.
|
||||
|
||||
Build Docker frontend superata, inclusi test del CSS compilato. Rimane l'avviso
|
||||
preesistente Vite sui bundle maggiori di 500 kB. Il CSS servito dal Mac include
|
||||
il rosso Omics, le azioni inline e la rimozione del bordo; configurazione full/en
|
||||
confermata. Container frontend `8a1608ad7fc6`, immagine `a2f489ebe9de`, healthy.
|
||||
Core `3c3c0739b9af`, catalogo `89755e439dc7`, Qdrant `52ebd5c47955` ed embedding
|
||||
`7f690e534eda` sono invariati e healthy.
|
||||
|
||||
## Aggiornamento e rollback
|
||||
|
||||
È stato ricostruito e ricreato soltanto il frontend attraverso il launcher
|
||||
`/private/tmp/thothii-memory-preview.sh`, con `up -d --no-deps --no-build --wait frontend`.
|
||||
L'immagine precedente è conservata come
|
||||
`thothii-frontend:before-header-layout-20260913`. Per ripristinarla sul Mac:
|
||||
|
||||
```bash
|
||||
docker image tag thothii-frontend:before-header-layout-20260913 thothii-frontend:local
|
||||
bash /private/tmp/thothii-memory-preview.sh up -d --no-deps --no-build --wait frontend
|
||||
```
|
||||
|
||||
Per tornare alla revisione nuova, ricostruire il frontend dal branch aggiornato
|
||||
e ripetere il comando di avvio. Non toccare volumi, Core o configurazione Omics.
|
||||
|
||||
## Follow-up: login e focus del selettore lingua
|
||||
|
||||
Rimossi dalla form login il soprattitolo «Accesso a ThothII», il relativo lucchetto
|
||||
decorativo e la spiegazione «Usa l’account della tua installazione per continuare.».
|
||||
Il titolo «Accedi a ThothII» rimane. La modifica vale in inglese e italiano.
|
||||
|
||||
I select nativi possono mantenere `:focus-visible` anche dopo un clic. Il selettore
|
||||
lingua distingue ora il focus da puntatore: niente outline esterno dopo il clic;
|
||||
il normale bordo del controllo rimane. Il ritorno con Tab e l'interazione da
|
||||
tastiera conservano l'indicatore visibile. Escape chiude il menu senza cambiare
|
||||
la modalità di focus. Nessuna sfocatura forzata o modifica all'header Omics.
|
||||
|
||||
Verificati 36 test LoginPage/AuthGate/AppShell.host e 14 scenari browser, inclusi
|
||||
login EN/IT e clic, Escape, Tab/Shift+Tab in entrambi i temi. Screenshot controllati;
|
||||
nessuna autenticazione reale o sessione utente è stata modificata dalle fixture.
|
||||
Typecheck e build Docker superati. Impeccable ha guidato la rimozione dei testi
|
||||
ridondanti mantenendo titolo principale e accessibilità da tastiera.
|
||||
|
||||
Solo il frontend Mac è stato ricreato, healthy: container `204efd40d3eb`, immagine
|
||||
`7dd0752ff823`. Il CSS effettivamente servito include la correzione del focus.
|
||||
Core, catalogo, Qdrant ed embedding sono invariati. Per annullare soltanto questo
|
||||
follow-up, usare nei comandi di rollback sopra il tag
|
||||
`thothii-frontend:before-login-focus-20260913`.
|
||||
|
||||
## Follow-up: comando Sessione unico e bordi completi
|
||||
|
||||
Il pulsante Session/Sessione sostituisce New session e Return to session. Una
|
||||
sessione aperta non finalizzata/archiviata, o una creazione già inviata in attesa
|
||||
di completamento, viene conservata e riportata in primo piano. Nessun reset,
|
||||
nuova ripresa o ricreazione della connessione eventi. In assenza di sessione in
|
||||
corso si prepara una nuova domanda attraverso il percorso esistente: controlli
|
||||
di contesto/preprocessing, protezione delle modifiche amministrative, prewarm e
|
||||
focus del campo. La sessione viene creata solo all'invio della domanda. Un pannello
|
||||
documentale non ripreso può essere riaperto dalla relativa voce nella lista.
|
||||
|
||||
I tab ricevono 3px aggiuntivi per lato orizzontale e 3px verticali, con altezza
|
||||
minima 38px e crescita per le etichette italiane su due righe. Tutti i bordi sono
|
||||
da 1px e dello stesso colore: grigio inattivo, rosso attivo. Rimossi il bordo
|
||||
del contenitore e il margine negativo; 4px separano i tab. Questa richiesta
|
||||
sostituisce la precedente rimozione del bordo inferiore.
|
||||
|
||||
Suite frontend completa: 757 test in 90 file; Playwright: 15 scenari. Superati
|
||||
anche typecheck, controllo di 1683 traduzioni italiane/1703 riferimenti statici
|
||||
e build Docker. Coperti ritorno senza seconda ripresa, clic durante creazione,
|
||||
assenza di creazione prima dell'invio, bozze amministrative e del composer,
|
||||
geometria/bordi EN/IT in chiaro e scuro e layout mobile/embedded. Le fixture
|
||||
bloccano le chiamate reali, incluso il prewarm. Screenshot italiani verificati.
|
||||
Impeccable ha guidato la spaziatura e la conservazione dello stato accessibile.
|
||||
|
||||
Il rollback di questo follow-up usa il tag
|
||||
`thothii-frontend:before-session-navigation-20260913` con i comandi sopra.
|
||||
Frontend Mac aggiornato e healthy: container `2844778d311c`, immagine `d58dccfee3f9`.
|
||||
Core e servizi dati rimangono quelli registrati sopra; nessun deploy Omics/PSD.
|
||||
@@ -0,0 +1,77 @@
|
||||
# Lettura di Evidence e Memory
|
||||
|
||||
Data: 13 settembre 2026. Richiesta: eliminare il muro di testo nelle regole,
|
||||
usare la larghezza disponibile, fornire Memory finte per la verifica grafica e
|
||||
sostituire i pulsanti Copia con l'icona a due fogli.
|
||||
|
||||
## Intervento
|
||||
|
||||
Rimossi il limite di 75ch dal dettaglio Evidence e quello di 72ch dai campi Memory.
|
||||
La variante di lettura Knowledge elimina anche il limite interno dei paragrafi
|
||||
Markdown, mantenendo il comportamento responsive del contenitore. Gli altri
|
||||
visualizzatori non cambiano impaginazione. Codice e identificatori lunghi possono
|
||||
andare a capo quando necessario, senza allargare la pagina.
|
||||
|
||||
Per paragrafi di almeno 360 caratteri, la variante introduce separazioni visive
|
||||
dopo almeno 180 caratteri, cercando punti, punti e virgola, punti interrogativi
|
||||
o esclamativi nel testo ordinario. Non divide dentro codice inline, enfasi o link;
|
||||
elenchi, titoli, paragrafi brevi e blocchi SQL già strutturati rimangono intatti.
|
||||
La spaziatura tra paragrafi è 1,25em. Si tratta di un intervento sul rendering
|
||||
Markdown, non di una riscrittura o un salvataggio dei documenti. Nessuna conoscenza
|
||||
di dominio viene generata dal visualizzatore.
|
||||
|
||||
Ambito, Provenienza e Regola occupano l'intera larghezza del dettaglio. Gli estratti
|
||||
di provenienza interpretano Markdown, senza mostrare letteralmente asterischi e
|
||||
backtick. Copia usa l'icona Lucide Copy con nome accessibile e tooltip; il percorso
|
||||
completo viene copiato senza trasformazioni e gli errori restano annunciati.
|
||||
|
||||
Impeccable ha guidato la leggibilità, la separazione dei paragrafi e l'accessibilità;
|
||||
la larghezza piena segue la richiesta esplicita dell'utente anche oltre la misura
|
||||
di lettura ordinaria del design system.
|
||||
|
||||
## Memory simulate
|
||||
|
||||
In **Administration → Memory → Formatting examples**, oppure **Amministrazione →
|
||||
Memory → Esempi di formattazione**, sono disponibili quattro schede FAKE:
|
||||
|
||||
- chiarimento di dominio con una regola lunga;
|
||||
- regola SQL con titoli, elenchi e identificatori;
|
||||
- domanda risolta con SQL dimostrativo;
|
||||
- errore spiegato con paragrafi distinti.
|
||||
|
||||
La sezione si apre automaticamente se l'archivio reale è vuoto. Gli esempi sono
|
||||
fixture frontend in `frontend/src/shell/memoryFormattingExamples.ts`, separate
|
||||
dai risultati dell'archivio e dai suoi conteggi. Riutilizzano il lettore reale,
|
||||
ma non offrono Edit/Delete/Save, non hanno dipendenze o link a schede reali e non
|
||||
vengono inviati ad alcuna API Memory. Nessun inserimento PostgreSQL, indicizzazione
|
||||
Qdrant, consolidamento Evidence o invio al modello è avvenuto. I nomi demo e gli
|
||||
identificatori non sono riferimenti al DWH operativo.
|
||||
|
||||
Si possono richiudere senza cancellazioni. Una futura rimozione degli esempi è
|
||||
una modifica del frontend, non una pulizia dei dati. New card dopo un esempio
|
||||
apre una scheda vuota, senza copiarne il contenuto simulato.
|
||||
|
||||
## Verifiche e consegna locale
|
||||
|
||||
- 762 test frontend in 91 file, tutti superati.
|
||||
- 18 scenari Playwright, inclusi reader a 390, 1280 e 2400 px, tema scuro,
|
||||
assenza di overflow, larghezza dei paragrafi e separazione effettiva.
|
||||
- Test di conservazione di parole, codice e destinazioni dei link, struttura
|
||||
Markdown e comportamento invariato dei visualizzatori ordinari.
|
||||
- Clipboard: contenuto copiato esatto, nome accessibile e fallimento gestito.
|
||||
- Fixture Memory: nessuna richiesta di scrittura o caricamento di una falsa
|
||||
scheda dal server; nessuna azione di modifica disponibile.
|
||||
- Typecheck, controllo di 1686 traduzioni italiane/1707 riferimenti statici e build
|
||||
Docker superati. Screenshot desktop, desktop largo e mobile scuro controllati.
|
||||
|
||||
Il Mac serve la nuova variante CSS. Solo frontend è stato ricreato, container
|
||||
`fc4286b5406d`, immagine `cbe0fe0dce55`, healthy. Core `3c3c0739b9af`, catalogo
|
||||
`89755e439dc7`, Qdrant `52ebd5c47955` ed embedding `7f690e534eda` restano invariati
|
||||
e healthy. Non è stato eseguito un deploy Omics o PSD.
|
||||
|
||||
Rollback locale, senza toccare altri servizi o volumi:
|
||||
|
||||
```bash
|
||||
docker image tag thothii-frontend:before-knowledge-reading-20260913 thothii-frontend:local
|
||||
bash /private/tmp/thothii-memory-preview.sh up -d --no-deps --no-build --wait frontend
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
# Tipografia condivisa per Memory ed Evidence
|
||||
|
||||
## Modifica
|
||||
|
||||
I lettori mescolavano etichette da 14px, sezioni da 16px e Markdown con una
|
||||
gerarchia indipendente. I blocchi di codice applicavano una riduzione relativa
|
||||
anche al carattere già ridotto del contenitore.
|
||||
|
||||
La regola condivisa in `frontend/src/index.css`, documentata in `DESIGN.md`, usa:
|
||||
|
||||
- Manrope per titolo, sezioni, paragrafi, elenchi e provenienza.
|
||||
- Titolo della scheda: 24px, peso 600, interlinea 1.3.
|
||||
- Titoli dei campi: 20px, peso 600, interlinea 1.4, 8px prima del contenuto.
|
||||
- Testo narrativo: 16px, peso 400, interlinea 1.65.
|
||||
- Sottotitoli Markdown interni: 16px, peso 600; non competono con il titolo del
|
||||
campo. I livelli semantici originali sono conservati.
|
||||
- Metadati: 14px; codice, percorsi e identificatori: monospaziato a 14px, senza
|
||||
riduzioni cumulative nei blocchi.
|
||||
- Sezioni distanziate di 24px; paragrafi consecutivi distanziati di 20px.
|
||||
|
||||
L'uso della skill Impeccable ha guidato la gerarchia a ruoli fissi e la scelta di
|
||||
un'unica famiglia, riutilizzando quella già distribuita dall'applicazione.
|
||||
Rimane valida la richiesta esplicita di occupare tutta la larghezza disponibile:
|
||||
nessun limite di riga in caratteri e nessuna riduzione dei font su mobile.
|
||||
Controlli, indici degli archivi e altri lettori non ricevono questa nuova scala.
|
||||
Documenti originali e schede salvate non sono stati riscritti; gli esempi FAKE
|
||||
restano esclusi da salvataggio, indicizzazione e uso da parte del modello.
|
||||
|
||||
## Verifiche
|
||||
|
||||
- Typecheck frontend e build Docker completati.
|
||||
- 762 test Vitest su 91 file e 18 scenari Playwright superati.
|
||||
- Controlli CSS calcolati a 390, 1280 e 2400px: famiglia, dimensioni, pesi,
|
||||
interlinea, margini, codice inline/fenced e sottotitoli Markdown da h1 a h6.
|
||||
- Ispezione delle schermate Evidence in light e Memory in dark, anche mobile.
|
||||
- Nessun overflow orizzontale; nessuna scrittura API negli scenari FAKE.
|
||||
- Catalogo i18n: 1686 messaggi italiani, 1707 riferimenti statici verificati.
|
||||
|
||||
## Installazione locale
|
||||
|
||||
Ricreato solo il frontend del progetto Docker `thothii-18998cca7b0a`:
|
||||
container `87fca0dc5e19`, immagine `19f1704b6bb2`, stato healthy.
|
||||
Il CSS servito da `http://127.0.0.1:8080` contiene le nuove regole condivise.
|
||||
Core, PostgreSQL, Qdrant ed embedding conservano i container precedenti.
|
||||
Nessuna modifica alla configurazione full/en, a Omics o al server PSD.
|
||||
|
||||
Ripristino della precedente immagine locale:
|
||||
|
||||
```bash
|
||||
docker image tag thothii-frontend:before-knowledge-typography-20260913 thothii-frontend:local
|
||||
bash /private/tmp/thothii-memory-preview.sh up -d --no-deps --no-build --wait frontend
|
||||
```
|
||||
@@ -0,0 +1,195 @@
|
||||
# Revisione della semplificazione della shell
|
||||
|
||||
Data: 2026-09-13. Oggetto: piano full/embedded, ADR 0021–0022 e contratto
|
||||
Portal Shell Adapter v1. Questa è una revisione con raccomandazioni: non modifica il
|
||||
codice applicativo né sostituisce automaticamente i contratti accettati.
|
||||
|
||||
## Valutazione
|
||||
|
||||
La separazione tra shell, autenticazione e lingua delle sessioni è corretta. La
|
||||
semplificazione precedente ha però mantenuto un protocollo di comunicazione non
|
||||
necessario per il montaggio corrente e ha lasciato ambigue alcune condizioni di
|
||||
compatibilità. Raccomando un adapter che osservi il documento già condiviso con
|
||||
Omics, riutilizzi l'autenticazione esistente e non imponga un nuovo bridge al portale.
|
||||
|
||||
La revisione considera il sorgente locale di ThothII e Omics Portal al commit
|
||||
`aff7581`, già ottenuto con il pull richiesto. Non certifica quali immagini,
|
||||
configurazioni o modifiche siano attualmente attive sul server.
|
||||
|
||||
## Problemi individuati e correzioni raccomandate
|
||||
|
||||
### 1. Il cambio lingua senza ricaricamento non corrisponde a Omics
|
||||
|
||||
In `templates/partials/topbar.html:74–87`, Omics usa il form Django `set_language`
|
||||
con `onchange="this.form.submit()"`. La lingua cambia attraverso una nuova pagina
|
||||
renderizzata dal server. Il criterio 2 del contratto v1 promette invece aggiornamenti
|
||||
senza ricaricamento per tutte le preferenze.
|
||||
|
||||
Raccomandazione: rispettare il comportamento del portale. In full, lingua e tema
|
||||
cambiano immediatamente. In embedded, il tema cambia immediatamente e la lingua
|
||||
segue il normale ricaricamento Omics. Evitare di intercettare il form per cambiare
|
||||
solo ThothII: lascerebbe header, sidebar e testi Django nella lingua precedente.
|
||||
|
||||
Il ricaricamento va verificato durante una sessione attiva e con modifiche non
|
||||
salvate: deve essere possibile ritrovare la sessione senza avviare una nuova
|
||||
generazione; eventuali bozze richiedono una protezione dalla navigazione. Lo stato
|
||||
persistito del workflow non equivale alla conservazione automatica della bozza UI
|
||||
o del flusso di messaggi in memoria. Questa verifica è necessaria anche mantenendo
|
||||
il protocollo a eventi del piano precedente.
|
||||
|
||||
### 2. Un protocollo ready/state non è necessario nello stesso documento
|
||||
|
||||
`templates/kokoro/datamart_builder.html` monta React in `#root`, nello stesso
|
||||
documento dell'header. L'adapter può ottenere direttamente:
|
||||
|
||||
- lingua effettivamente renderizzata: `data-lang` del selettore
|
||||
`.omics-language-select`;
|
||||
- tema: attributo `data-bs-theme` sull'elemento `html`;
|
||||
- fullscreen: stato del documento e relativo evento del browser.
|
||||
|
||||
Un'osservazione limitata all'attributo del tema e un listener del fullscreen
|
||||
coprono gli aggiornamenti attuali. La lingua viene riletta quando Django restituisce
|
||||
la pagina. Questi selettori e dettagli devono comparire soltanto dentro
|
||||
`OmicsPortalAdapter`, con test basati sul template reale.
|
||||
|
||||
Attenzione: `templates/base.html:3` contiene oggi `lang="en"` fisso; quell'attributo
|
||||
non è una fonte attendibile per la lingua Omics. Se in futuro il portale espone la
|
||||
lingua su un attributo dedicato del punto di montaggio, si modifica soltanto l'adapter.
|
||||
|
||||
La proposta elimina due eventi personalizzati, la versione del protocollo, il
|
||||
timeout di avvio e il rischio che il messaggio iniziale parta prima del listener.
|
||||
L'osservazione va installata prima di consegnare lo snapshot iniziale; la funzione
|
||||
di disiscrizione rimuove tutte le risorse. L'assenza dei dati Omics attesi produce
|
||||
un errore di integrazione comprensibile, senza attivare la shell full.
|
||||
|
||||
Il costo accettato è una dipendenza esplicita dal piccolo contratto DOM Omics,
|
||||
confinata nell'adapter. Un secondo portale potrà fornire gli stessi dati usando
|
||||
un'altra implementazione, anche con un diverso trasporto. Non occorre costruirla ora.
|
||||
|
||||
### 3. `authenticated` duplica uno stato che il server già verifica
|
||||
|
||||
`kokoro/datamart_catalog_views.py:49` e `nginx/nginx.conf:69` verificano l'accesso
|
||||
Omics e trasmettono al backend identità e autorizzazioni normalizzate. ThothII
|
||||
ottiene già l'utente tramite `/me`. Non serve un ulteriore login né un flag nel
|
||||
documento che dichiari l'utente autenticato.
|
||||
|
||||
Il logout Omics attuale è una navigazione (`topbar.html:118`), non un evento di
|
||||
revoca. Un click sul link non prova che il logout sia stato completato; inoltre,
|
||||
un flag inviato una volta non rileva la scadenza della sessione o un logout in
|
||||
un'altra scheda.
|
||||
|
||||
Raccomandazione: togliere `authenticated` dallo snapshot visivo. La verifica
|
||||
dell'accesso rimane nel percorso di autenticazione esistente. In embedded,
|
||||
perdita dell'accesso significa chiudere i dati protetti e demandare il rientro
|
||||
al portale, senza mostrare il form di login ThothII.
|
||||
|
||||
Serve verificare la gestione dei rifiuti Omics: l'endpoint di autorizzazione
|
||||
restituisce attualmente 403 anche quando l'accesso non è disponibile, mentre
|
||||
`frontend/src/api/client.ts` pulisce automaticamente lo stato su 401. Un 403
|
||||
ordinario può anche significare che manca il permesso per una sola operazione;
|
||||
non va trasformato indiscriminatamente in logout. La verifica `/me` deve
|
||||
distinguere la perdita di accesso all'applicazione dal rifiuto di una sua funzione.
|
||||
|
||||
`frontend/src/stream/useSessionStream.ts` esegue già un controllo di autenticazione
|
||||
quando il collegamento eventi fallisce: riutilizzare quel percorso. Non promettere
|
||||
revoca istantanea di una connessione già aperta in un'altra scheda sulla sola base
|
||||
di `auth_request` o di un evento nella pagina corrente. Il contratto deve dichiarare
|
||||
quando l'accesso viene ricontrollato e verificare anche il ritorno a una scheda
|
||||
rimasta aperta.
|
||||
|
||||
In full sul Mac resta il login locale esistente. Il logout backend esiste già
|
||||
(`backend/src/auth/routes.ts:355`): il lavoro riguarda il collegamento all'header
|
||||
e la pulizia della UI. Per installazioni full con OIDC va consentito anche quel
|
||||
logout; oggi `AuthGate` lo espone soltanto per `mode === "local"`. La revoca della
|
||||
sessione ThothII non va descritta come logout globale dal fornitore d'identità.
|
||||
|
||||
### 4. Il default embedded contraddice l'adapter obbligatorio
|
||||
|
||||
Il piano dichiara compatibilità con descrittori senza `shell`, ma il contratto
|
||||
richiede `adapter` in embedded. Inoltre, pretendere un nuovo bridge renderebbe
|
||||
inutilizzabile la vecchia pagina Omics finché non fosse aggiornata.
|
||||
|
||||
Raccomandazione: risolvere i valori in un unico punto di configurazione:
|
||||
|
||||
- assenza di `shell`: embedded con adapter Omics predefinito;
|
||||
- embedded senza `adapter`: `omics-portal`;
|
||||
- full: nessun adapter istanziato;
|
||||
- nome adapter sconosciuto: errore esplicito di configurazione.
|
||||
|
||||
L'adapter che legge lo stato già esistente rende questa compatibilità concreta.
|
||||
Sul Mac rimangono espliciti `mode: full` e `defaultLocale: en`. La proiezione
|
||||
pubblica può usare il `config.js` già presente; non serve un nuovo servizio di
|
||||
configurazione. Va verificato anche il prefisso API `/datamart-builder/api` nel
|
||||
montaggio Omics: il default frontend `/api` non basta a dimostrare che il deploy
|
||||
funzioni. Prima si aggiorna il lettore del descrittore, poi il file installato,
|
||||
poiché il lettore corrente rifiuta chiavi sconosciute.
|
||||
|
||||
### 5. Fullscreen e dark mode hanno già elementi riutilizzabili
|
||||
|
||||
ThothII possiede già token scuri in `frontend/src/index.css:67`, attivati anche da
|
||||
`data-bs-theme="dark"`. Il lavoro è completarne la copertura e verificare contrasto,
|
||||
form, menu e finestre, riutilizzando questi token.
|
||||
|
||||
Omics cambia la classe `fullscreen-enable` al click (`static/js/app.js:702`)
|
||||
prima di conoscere il risultato. Il ramo di uscita usa metodi storici e non
|
||||
contiene `document.exitFullscreen()`. Non va copiato nella shell full: l'icona
|
||||
deve seguire lo stato effettivo, compresi Esc e richieste rifiutate. La correzione
|
||||
equivalente dell'header Omics appartiene al suo modulo UI, non a un secondo
|
||||
controllo fullscreen dentro ThothII embedded.
|
||||
|
||||
La fascia vuota sinistra si realizza con una misura CSS condivisa, almeno 20 px,
|
||||
bilanciata con lo spazio destro. Non richiede un modulo di navigazione vuoto.
|
||||
Poiché il documento è condiviso, verificare anche che stili globali ThothII e
|
||||
contenuti sovrapposti non alterino header e sidebar del portale: il template Omics
|
||||
contiene già correzioni per reset CSS e altezza `100vh`.
|
||||
|
||||
## Elementi da conservare
|
||||
|
||||
La lingua dell'interfaccia, quella delle domande al revisore e quella dei contenuti
|
||||
del workspace hanno proprietari e durate diverse. Conservare la separazione di
|
||||
ADR 0022: semplificarla in un'unica preferenza globale introdurrebbe errori in
|
||||
ripresa e nei workspace italiani.
|
||||
|
||||
Precisare tre regole d'implementazione:
|
||||
|
||||
- una nuova sessione salva il locale UI effettivamente risolto, dopo il fallback
|
||||
delle traduzioni;
|
||||
- una sessione esistente conserva la propria lingua anche se un altro revisore
|
||||
usa un'interfaccia diversa;
|
||||
- per manifest precedenti senza campo lingua, usare la lingua del workspace come
|
||||
criterio di compatibilità e fissarla alla prima ripresa con un aggiornamento
|
||||
idempotente. Non dedurla dalla lingua del browser del nuovo revisore. La lingua
|
||||
storica esatta non è ricostruibile se il workspace è stato cambiato nel frattempo.
|
||||
|
||||
L'i18n resta il lavoro trasversale principale: include pagine amministrative,
|
||||
errori, accessibilità e testi deterministici dei widget, anche quelli costruiti
|
||||
fuori da React. Aggiungere soltanto i cataloghi dell'header non soddisfa la richiesta.
|
||||
Il modello deve ricevere la lingua dal manifest autorevole, senza tradurre a
|
||||
posteriori payload delle decisioni, SQL o contenuti del workspace.
|
||||
|
||||
## Struttura raccomandata
|
||||
|
||||
Un solo controller di shell alimenta l'interfaccia. In full gestisce preferenze
|
||||
locali e header; in embedded riceve `{ locale, theme, fullscreen }` da un
|
||||
`PortalAdapter.subscribe(...)`. I componenti applicativi usano quello stato e
|
||||
non conoscono Omics. Nessun registro dinamico di plugin, protocollo di comandi o
|
||||
controller separato per ciascun pulsante.
|
||||
|
||||
L'autenticazione continua a usare il modulo esistente, con presentazione dell'accesso
|
||||
coerente con la shell. L'integrazione con un futuro portale richiede anche che il
|
||||
suo lato server soddisfi il contratto di identità verificata: sostituire una classe
|
||||
JavaScript non può da solo sostituire l'autenticazione server. Documentare insieme
|
||||
l'adapter UI e la configurazione server Omics, senza introdurre nuove dipendenze
|
||||
Omics nel workflow o nelle pagine ThothII.
|
||||
|
||||
## Verifiche necessarie prima della consegna
|
||||
|
||||
Verificare full sul Mac con default inglese, accesso/logout, tema e fullscreen;
|
||||
embedded sul template Omics, con preferenze già impostate prima del montaggio,
|
||||
cambio tema e lingua, Esc, assenza di header ThothII e descrittore precedente.
|
||||
Verificare nuova sessione, ripresa, manifest precedente, ricaricamento durante
|
||||
la revisione e perdita dell'accesso con collegamento eventi attivo.
|
||||
|
||||
Sono verifiche del comportamento, non motivi per costruire un'infrastruttura
|
||||
generica. Questa revisione si basa sull'ispezione del sorgente; non sono stati
|
||||
eseguiti test runtime né modificati i due applicativi.
|
||||
@@ -0,0 +1,125 @@
|
||||
# Integrazione della revisione grafica con full/embedded
|
||||
|
||||
Data: 2026-09-13. Ambito autorizzato: integrazione locale e aggiornamento del Mac,
|
||||
senza push, merge in `main` o deploy sul server PSD.
|
||||
|
||||
## Causa della regressione
|
||||
|
||||
La revisione full/embedded `d8a29bfb` e il ramo `codex/ui-visual-review` partivano
|
||||
entrambi da `2d1b714e`. La prima build full è stata eseguita dal primo ramo senza
|
||||
integrare i sette commit grafici già presenti nell'immagine installata sul Mac.
|
||||
La corrispondenza è verificata anche sulle immagini: il backup
|
||||
`thothii-frontend:before-full-shell-20260913` e
|
||||
`thothii-frontend:visual-review-20260912` identificano entrambi `7dceaafcd9ee`.
|
||||
|
||||
Commit recuperati, in ordine:
|
||||
|
||||
| Commit | Modifica |
|
||||
| --- | --- |
|
||||
| `c8d276dd` | Manrope locale, scala tipografica condivisa, leggibilità delle pagine operative |
|
||||
| `eed398e5` | Marchio ThothII a 48 px nel Core e 32 px nella sidebar |
|
||||
| `8c819968` | Indicatori del catalogo dopo le rispettive etichette |
|
||||
| `803e9e92` | Ricalcolo dell'altezza del campo domanda dopo la riapertura del Core |
|
||||
| `e088abd6` | Allineamento degli stati alla griglia del riepilogo |
|
||||
| `5af44081` | Margini e assi interni dei blocchi Database |
|
||||
| `a59624a6` | Allineamento del pannello del contesto e rimozione delle spiegazioni ridondanti |
|
||||
|
||||
## Criteri di riconciliazione
|
||||
|
||||
- Conservati traduzioni, protezione delle bozze, autenticazione, gestione delle
|
||||
sessioni e isolamento dell'adapter Omics introdotti dalla revisione full.
|
||||
- Recuperati font locale, classi e geometria approvati nel ramo grafico.
|
||||
Impeccable, registro product, ha guidato la verifica della coerenza; nessun
|
||||
ridisegno delle pagine o nuovo accorciamento dei loro titoli.
|
||||
- Il reset e i token CSS restano circoscritti al mount di ThothII e ai suoi popup:
|
||||
la revisione grafica non reintroduce un reset del documento del portale.
|
||||
- Conservati tema, traduzioni e stato di AG Grid; le colorazioni degli avvisi
|
||||
rimangono leggibili nei due temi.
|
||||
- Tradotte le nuove etichette e le spiegazioni introdotte dalla revisione grafica.
|
||||
- Il mock di ResizeObserver dei test ora emette le misure degli elementi osservati,
|
||||
come richiesto anche dal ridimensionamento del campo domanda recuperato.
|
||||
- I test visuali configurano esplicitamente full oppure embedded. La simulazione
|
||||
embedded fornisce le preferenze del portale e il suo reset del margine del body;
|
||||
ThothII non deve applicare quel reset al documento esterno.
|
||||
|
||||
## Verifiche
|
||||
|
||||
| Controllo | Esito |
|
||||
| --- | --- |
|
||||
| Suite frontend completa | 755 test passati, zero fallimenti |
|
||||
| Playwright visuale/interazione | 11 scenari passati, zero saltati o instabili |
|
||||
| Larghezze della revisione grafica | 390, 649, 768, 1280 e 1600 px |
|
||||
| Combinazione lingua/tema/full | EN/IT, chiaro/scuro, persistenza al reload e margini simmetrici a 390 e 1280 px |
|
||||
| Caricamento font | Verificata una font face Manrope Variable effettivamente caricata |
|
||||
| Embedded | Nessun header ThothII, contenimento sotto header e sidebar del portale simulato |
|
||||
| Cataloghi | 1681 messaggi italiani, 1706 riferimenti statici; nessuna chiave mancante o interpolazione incoerente |
|
||||
| Typecheck e build | Superati, inclusa la regressione sul CSS compilato prima della build |
|
||||
| Documentazione | Build MkDocs strict superata |
|
||||
|
||||
Le verifiche Playwright usano dati sintetici e bloccano tutte le richieste API;
|
||||
gli scenari non avviano modelli reali né modificano dati dell'installazione.
|
||||
Gli screenshot sono in `frontend/test-results/visual-review/`, ignorati da Git.
|
||||
Backend, harness e Omics non sono modificati da questa integrazione; le loro
|
||||
verifiche precedenti restano nel rapporto full-shell. Non viene rivendicata una
|
||||
nuova verifica end-to-end sul portale di produzione.
|
||||
|
||||
La verifica indipendente dell'integrazione di CSS, shell e reset non ha segnalato
|
||||
rilievi aperti. Il controllo della pagina reale ha inoltre rilevato l'etichetta
|
||||
predefinita «Administration» non tradotta: è stata corretta nel componente condiviso
|
||||
e coperta dallo scenario EN/IT. Nessun nuovo testo JSX o attributo di accessibilità
|
||||
non tradotto è stato introdotto dal merge, secondo il confronto statico con `d8a29bfb`.
|
||||
|
||||
## Aggiornamento e rollback locali
|
||||
|
||||
Contesto di build: `/Users/mp/projects/ThothII`; launcher dell'installazione:
|
||||
`/private/tmp/thothii-memory-preview.sh`. Il launcher termina con l'override
|
||||
`/private/tmp/thothii-context-a.compose.yaml`, che seleziona questo checkout.
|
||||
Non applicare l'override della precedente revisione isolata: selezionerebbe di nuovo
|
||||
il worktree senza l'integrazione full/embedded.
|
||||
|
||||
Comandi usati per costruire e sostituire il solo frontend:
|
||||
|
||||
```sh
|
||||
bash /private/tmp/thothii-memory-preview.sh build frontend
|
||||
bash /private/tmp/thothii-memory-preview.sh up -d --no-deps --no-build --wait frontend
|
||||
```
|
||||
|
||||
Configurazione Mac conservata: modalità `full`, lingua predefinita `en`.
|
||||
Aggiornamento completato alle 12:54 UTC: immagine frontend `605a6e6bba68`, container
|
||||
`9489a5765f7b`, stato healthy. Core (`3c3c0739b9af`), catalogo (`89755e439dc7`),
|
||||
Qdrant (`52ebd5c47955`) ed embedding (`7f690e534eda`) conservano gli stessi container,
|
||||
immagini e tempi di avvio rilevati prima dell'aggiornamento; sono tutti healthy.
|
||||
Il controllo dal browser usa l'accesso locale già presente, senza logout, modifica
|
||||
del catalogo o avvio di una sessione del modello. Sul viewport reale da 771 px:
|
||||
titolo Manrope Variable a 24 px, margini full sinistro/destro di 24 px, tre blocchi
|
||||
Database con identica posizione x=45 e larghezza 681 px; nessun overflow della pagina.
|
||||
Verificati italiano e tema scuro; ripristinati inglese e tema chiaro.
|
||||
|
||||
L'immagine prima del merge è conservata come
|
||||
`thothii-frontend:before-visual-shell-merge-20260913` (`781650644192`). Per ripristinare
|
||||
quella versione full precedente, senza toccare Core o i volumi:
|
||||
|
||||
```sh
|
||||
bash /private/tmp/thothii-memory-preview.sh \
|
||||
-f /Users/mp/projects/ThothII/deploy/compose.visual-shell-rollback.yaml \
|
||||
up -d --no-deps --no-build --wait frontend
|
||||
```
|
||||
|
||||
Quel rollback reintroduce volutamente l'aspetto precedente al recupero grafico.
|
||||
Per tornare alla versione integrata usare il launcher senza l'override di rollback.
|
||||
Le immagini della revisione grafica isolata rimangono disponibili, ma non includono
|
||||
le nuove funzionalità full/embedded: non sono il rollback equivalente di questa consegna.
|
||||
|
||||
## Conservazione del lavoro locale e prevenzione
|
||||
|
||||
Le tre modifiche documentali locali preesistenti sono state protette nello stash
|
||||
`436d59225869aa3d93ee04077c566d371bde4099`. I due rapporti erano identici alle versioni
|
||||
del ramo grafico; tutte le aggiunte di PROJECT_STATE erano già contenute nel merge.
|
||||
Non è stato necessario riapplicarle o sovrascrivere le versioni integrate. Lo stash
|
||||
è conservato come ulteriore copia recuperabile.
|
||||
|
||||
Prima di un successivo rebuild, confrontare il ramo corrente con gli altri worktree
|
||||
attivi e controllare il contesto di build effettivo del launcher. Un'immagine locale
|
||||
può provenire da un ramo laterale più recente del checkout principale. Il passaggio
|
||||
delle sole suite funzionali non certifica che la build contenga la revisione grafica
|
||||
già accettata: verificare anche l'ascendenza Git e i test visuali recuperati qui.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Dialog di sessione: rilascio server del 14 settembre 2026
|
||||
|
||||
Aggiornamento autorizzato dall'utente ed eseguito alle 18:09 CEST. Il solo frontend
|
||||
è stato ricreato; core e Omics web mantengono ID e timestamp di avvio precedenti.
|
||||
La modifica comprende dialog di sessione più ampi e contenuti nella vista,
|
||||
conferme sopra e sotto le form, e l'etichetta To Administration / Vai
|
||||
all’Amministrazione. Le superfici amministrative e il workflow restano invariati.
|
||||
|
||||
## Provenienza e configurazione
|
||||
|
||||
- Base sorgente: `b1723c34`, più le modifiche frontend della working tree verificate.
|
||||
- Checkout di build: `/home/chirone/Thoth`; i 32 file frontend interessati sono
|
||||
stati allineati anche in `/srv/thothii-v2/source/ThothII`, conservando i precedenti.
|
||||
- Immagine: `thothii-v2-frontend:b1723c34-session-dialogs-20260914`.
|
||||
- Image ID: `sha256:d2ed3dec42f8a56536ebbc8d74f13892d4c42c9a7f2fb67c476ff39f43fe7af9`.
|
||||
- Container: `becadeb12b5d9bd380700813e1f489e7f5674575b98ea0d00c6b7d751c890278`.
|
||||
- Avvio: `2026-09-14T16:09:12.835900768Z`.
|
||||
- Il solo campo `services.frontend.image` dell'override operativo
|
||||
`/srv/thothii-v2/operator/compose.portal-upstream.yaml` è fissato al nuovo tag.
|
||||
Il tag condiviso in `operator.env` non è cambiato: core e job mantengono
|
||||
`49333a2d-session-memory-fix`. I prossimi aggiornamenti frontend devono aggiornare
|
||||
esplicitamente questo campo, oppure ripristinarne l'interpolazione condivisa.
|
||||
- Nessuna migrazione, modifica di dati, credenziali, modello o auth.
|
||||
|
||||
## Verifiche
|
||||
|
||||
Prima della distribuzione: 778 test frontend, cinque scenari browser responsive
|
||||
(320/390/844/1280/1440 px, full e embedded), typecheck, traduzioni, build Vite e
|
||||
Docker. Smoke della configurazione embedded montata nella nuova immagine superato.
|
||||
|
||||
Dopo la distribuzione:
|
||||
|
||||
- frontend healthy, core e Omics web invariati e healthy;
|
||||
- `nginx -t` e reload Omics riusciti;
|
||||
- config embedded e asset nuovi HTTP 200 tramite nginx Omics locale con Host reale;
|
||||
- JavaScript `index-inK74FWS.js` contiene entrambe le nuove etichette;
|
||||
- CSS `index-4WPDUJu7.css` contiene le regole `.thot-session-dialog`;
|
||||
- manifest nuovo raggiungibile dal container Omics; trascorso il TTL di 30 secondi;
|
||||
- API `/me` senza login ancora HTTP 403;
|
||||
- `tht doctor --json`: `ok: true`, 13/13 controlli superati.
|
||||
|
||||
I test browser usano dati simulati; l'accettazione della resa nella sessione
|
||||
Omics autenticata dell'utente richiede di ricaricare la pagina. Non sono state
|
||||
create sessioni reali né invocati modelli per il collaudo.
|
||||
|
||||
## Backup e rollback
|
||||
|
||||
Directory protetta: `/srv/thothii-v2/backups/20260914-session-dialogs` (0700).
|
||||
Contiene override precedente, archivi sorgente prima/dopo, patch, inventario dei
|
||||
container e checksum verificati. L'immagine precedente è conservata anche come
|
||||
`thothii-v2-frontend:before-session-dialogs-20260914`.
|
||||
|
||||
Il launcher `compose.sh` nel backup conserva esattamente progetto, directory,
|
||||
env file e ordine dei cinque file Compose della distribuzione. Rilascio eseguito:
|
||||
|
||||
```bash
|
||||
sudo /srv/thothii-v2/backups/20260914-session-dialogs/compose.sh \
|
||||
up -d --no-deps --no-build --wait --wait-timeout 90 frontend
|
||||
```
|
||||
|
||||
Rollback applicativo, dopo aver verificato che non ci siano release successive:
|
||||
|
||||
```bash
|
||||
sudo cp -p /srv/thothii-v2/backups/20260914-session-dialogs/compose.portal-upstream.yaml \
|
||||
/srv/thothii-v2/operator/compose.portal-upstream.yaml
|
||||
sudo /srv/thothii-v2/backups/20260914-session-dialogs/compose.sh \
|
||||
up -d --no-deps --no-build --wait --wait-timeout 90 frontend
|
||||
sudo docker exec omics_portal-nginx-1 nginx -t
|
||||
sudo docker exec omics_portal-nginx-1 nginx -s reload
|
||||
```
|
||||
|
||||
Il ripristino dei sorgenti è separato: gli archivi conservano esattamente i file
|
||||
interessati. Un rollback grafico non richiede ripristino di database o indici.
|
||||
@@ -0,0 +1,148 @@
|
||||
# Correzione input sessione embedded e Memory vuota
|
||||
|
||||
## Stato
|
||||
|
||||
**Rilascio operativo eseguito il 14 settembre 2026 alle 17:18 CEST**, dopo
|
||||
l'autorizzazione esplicita del proprietario al riavvio. Core e frontend sono healthy;
|
||||
le nuove ammissioni sono riaperte (`active: false`, `admissions: 0`). Non risultavano
|
||||
processi Pi RPC attivi prima del fermo. L'inventario resta identico: una sessione
|
||||
`open` e una `closed`, entrambe non archiviate.
|
||||
|
||||
Il checkout operativo `/srv/thothii-v2/source/ThothII` è stato aggiornato in
|
||||
fast-forward al commit Gitea `d6cdffea629daf92cae8392eb1ebb3bb6f275f55`.
|
||||
|
||||
## Cause e correzioni
|
||||
|
||||
- La nuova `.thot-host` usa `100dvh`; Omics limita invece `#root` allo spazio
|
||||
sotto il topbar e ne nasconde l'overflow. La prova browser riproduce controlli
|
||||
che terminano a 821 px con il contenitore che termina a 782 px. La shell
|
||||
embedded ora ha `max-height: 100%`, così rispetta il contenitore; il fallback
|
||||
alla viewport e il contratto `--thoth-app-height` restano utilizzabili.
|
||||
- Nell'installazione reale PostgreSQL contiene zero Memory Card e la collection
|
||||
`psd-clinical-memory` zero punti, senza vettore sparse BM25. Il workflow
|
||||
interrogava comunque embedding/Qdrant e trasformava `BM25 collection
|
||||
configuration mismatch` in `memory_unavailable`, status 503. Il recupero ora
|
||||
restituisce `[]` dopo aver verificato in PostgreSQL che l'archivio è vuoto.
|
||||
Gli errori dell'archivio autorevole continuano a propagarsi. `memory rules`
|
||||
calcola il vettore soltanto se serve e lo condivide fra le due famiglie.
|
||||
|
||||
Nessuna migrazione, modifica di card, indice, DWH o autenticazione è necessaria.
|
||||
|
||||
## Verifiche eseguite
|
||||
|
||||
- Riproduzione live: `tht memory search` restituiva 503.
|
||||
- Confronto delle immagini attuale/candidata, con PostgreSQL e Qdrant reali e
|
||||
montaggi read-only: attuale exit 1/status 503; candidata exit 0/`[]`. La
|
||||
configurazione diagnostica non contiene credenziali DWH e non interroga il DWH.
|
||||
- 54 test Memory superati, 1 skipped, 2 deselected secondo la configurazione
|
||||
pytest; inclusi test PostgreSQL/Qdrant reali e regressione CLI archivio vuoto.
|
||||
- 90 test frontend superati: shell host, composer, creazione e gestione sessioni.
|
||||
- 5 scenari Playwright superati: sessione attiva embedded a 390/1280 px con
|
||||
input multilinea e apertura del dialogo di arresto; composer full dopo
|
||||
navigazione amministrativa; geometria host con header/rail.
|
||||
- TypeScript, build frontend, Ruff sui file Python modificati, `git diff --check`
|
||||
e scansione layout superati. Entrambe le build Docker completate;
|
||||
smoke della configurazione frontend superato.
|
||||
- Screenshot verificati in `frontend/test-results/visual-review/`.
|
||||
|
||||
## Immagini distribuite e controlli server
|
||||
|
||||
Le immagini candidate già collaudate sono quelle ora in esecuzione. Container core
|
||||
`1e71b0abd5aa` e frontend `45387534e8ad` avviati rispettivamente alle 15:18:43 e
|
||||
15:18:49 UTC. Catalogo, Qdrant, embedding e Omics web non sono stati ricreati.
|
||||
Nginx Omics è stato verificato e ricaricato per risolvere gli indirizzi aggiornati.
|
||||
|
||||
| Immagine distribuita | ID |
|
||||
| --- | --- |
|
||||
| `thothii-v2-core:49333a2d-session-memory-fix` | `sha256:ff4c435abd67c57e1e91e6e560dae73e67350ca499a5aedca3ffa517b9f59ee0` |
|
||||
| `thothii-v2-frontend:49333a2d-session-memory-fix` | `sha256:35933317769f3e12953f3b144d51f8fc2e7e9f7c4830eba80cc626f757f5bf0d` |
|
||||
|
||||
Controlli dopo il riavvio:
|
||||
|
||||
- `memory search` e `memory solved-search` nel core distribuito: exit 0, `[]`.
|
||||
- `workflow-doctor`: `ready: true`, un workspace; inventario sessioni invariato.
|
||||
- HTTP `/health`: `status: ok`; tutti i servizi richiesti healthy.
|
||||
- Omics serve config embedded/en e asset con HTTP 200: `index-BpY9Lzwz.js`,
|
||||
`index-BhJrKSGn.css`; verificata nel CSS la regola di altezza corretta.
|
||||
- `/datamart-builder/api/me` senza login continua a rispondere 403.
|
||||
- `nginx -t` superato; reload completato; TTL manifest Django trascorso.
|
||||
- `tht status`: exit 0; `tht doctor --json`: `ok: true`, 13/13 controlli passati.
|
||||
- Nessun errore di avvio rilevato nei log core.
|
||||
|
||||
Backup protetto in `/srv/thothii-v2/backups/20260914-session-memory-fix`
|
||||
(directory 0700): operator.env, descriptor e override precedenti, archivio di data,
|
||||
workspace-registry e Pi creato a core fermo, dump logico PostgreSQL e snapshot nativo
|
||||
Qdrant. Elenco tar e `pg_restore --list` validati; tutti gli SHA256 verificati.
|
||||
Le immagini precedenti restano anche con tag `before-session-memory-fix-20260914`.
|
||||
Nessuna migrazione o modifica al DWH. Il rollback normale resta applicativo.
|
||||
|
||||
## Comandi di rilascio e diagnostica
|
||||
|
||||
Il seguente launcher conserva progetto, env file e ordine degli override. Le
|
||||
ammissioni sono state bloccate e il core fermato prima del backup:
|
||||
|
||||
```bash
|
||||
thoth_fix_compose() {
|
||||
sudo docker compose --project-name thothii-7f901b48fe35 \
|
||||
--project-directory /srv/thothii-v2/source/ThothII \
|
||||
--env-file /srv/thothii-v2/operator/operator.env \
|
||||
-f /srv/thothii-v2/source/ThothII/compose.yaml \
|
||||
-f /srv/thothii-v2/source/ThothII/deploy/compose.server.yaml \
|
||||
-f /srv/thothii-v2/source/ThothII/deploy/compose.git-ssh.yaml \
|
||||
-f /srv/thothii-v2/operator/compose.portal-upstream.yaml \
|
||||
-f /srv/thothii-v2/source/ThothII/deploy/psd-server-v2/generated/compose.models.yaml "$@"
|
||||
}
|
||||
thoth_fix_compose exec -T core node /app/backend/dist/operator-command.js maintenance-activate
|
||||
thoth_fix_compose exec -T core node /app/backend/dist/operator-command.js maintenance-status
|
||||
thoth_fix_compose stop --timeout 45 core
|
||||
```
|
||||
|
||||
Dopo il backup è stato aggiornato esclusivamente `THTII_RELEASE_IMAGE_TAG` in
|
||||
`/srv/thothii-v2/operator/operator.env` a `49333a2d-session-memory-fix`, preservando
|
||||
altri valori, proprietario e permessi. Avvio e reload eseguiti:
|
||||
|
||||
```bash
|
||||
thoth_fix_compose up -d --no-deps --no-build core frontend
|
||||
sudo docker exec omics_portal-nginx-1 nginx -t
|
||||
sudo docker exec omics_portal-nginx-1 nginx -s reload
|
||||
|
||||
```
|
||||
|
||||
Il CLI legge i segreti soltanto con l'UID proprietario (10001). L'invocazione
|
||||
come root viene rifiutata dal controllo di proprietà; nessun file segreto è stato
|
||||
modificato. Per la diagnostica è stata usata una configurazione Docker temporanea
|
||||
vuota, evitando la directory `/root/.docker` inaccessibile a quell'UID:
|
||||
|
||||
```bash
|
||||
sudo install -d -m 0700 -o 10001 -g 1006 /tmp/thoth-owner-docker
|
||||
thoth_fix_cli() {
|
||||
sudo env DOCKER_CONFIG=/tmp/thoth-owner-docker \
|
||||
setpriv --reuid=10001 --regid=1006 --groups=1006,1014,988 \
|
||||
/usr/local/bin/tht --installation \
|
||||
/srv/thothii-v2/source/ThothII/deploy/psd-server-v2/thothii-installation.yaml "$@"
|
||||
}
|
||||
thoth_fix_cli status
|
||||
thoth_fix_cli doctor --json
|
||||
```
|
||||
|
||||
Riapertura dopo i controlli runtime:
|
||||
|
||||
```bash
|
||||
thoth_fix_compose exec -T core node /app/backend/dist/operator-command.js maintenance-deactivate
|
||||
```
|
||||
|
||||
Rollback applicativo: ripristinare l'operator.env protetto, ricreare solo
|
||||
core/frontend con lo stesso launcher, verificare e ricaricare nginx. Per riallineare
|
||||
anche i sorgenti preparare il revert del solo commit `d6cdffea`, preservando le
|
||||
modifiche successive. Non occorre ripristinare
|
||||
PostgreSQL o indici per un rollback di queste due correzioni.
|
||||
|
||||
|
||||
## Accettazione interattiva
|
||||
|
||||
Le prove browser automatiche su input e arresto sono passate prima del rilascio;
|
||||
la distribuzione degli asset corretti è verificata attraverso il proxy reale.
|
||||
Resta da confermare il comportamento nella sessione autenticata del proprietario,
|
||||
ricaricando la pagina Omics. Il collaudo non ha creato sessioni workflow reali né
|
||||
invocato un modello generativo; non sostituisce l'accettazione interattiva completa
|
||||
Omics/IdP documentata nella matrice di autenticazione.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Knowledge archives: consolidated implementation evidence
|
||||
|
||||
Consolidated on 15 September 2026 from the M1–M3, E1–E3 and X1 records of 8–9 September.
|
||||
This is historical verification evidence, not a claim that these test counts describe today's
|
||||
tree or that every installation has passed acceptance. Original commands, detailed outcomes and
|
||||
local deployment details remain under `docs/plans/` in Git commit
|
||||
`5f3a7f5975b96fae1e1cdd0da08b4d60d41064cc`.
|
||||
|
||||
| Increment | Delivered boundary | Recorded verification |
|
||||
| --- | --- | --- |
|
||||
| M1 | PostgreSQL Memory authority, administration, durable indexing retry | 1,134 harness + 9 portable cases; 17 real PostgreSQL/Qdrant cases; 190 Pi gates; 632 frontend. One backend auth timeout passed its isolated rerun. |
|
||||
| M2 | Dense/BM25 recall, scoped links and explicit projection rebuild | 1,152 harness; 78 targeted cases with real embedding; 13 Fastify API cases; 10 wheel/CLI cases. |
|
||||
| M3 | Human Memory promotion, receipts and physical-schema dependency cleanup | 1,152 harness + 9 portable; 41 Memory integration, 1 optional embedding skipped, 1 L2 excluded; 195 Pi gates; 635 frontend; 5 Catalog integration. Backend timing case passed isolated rerun. |
|
||||
| E1 | Editable file authority and explicit consolidation | 1,180 harness + 9 portable; real Qdrant including optional 35-unit PSD probe. No actual PSD authoring checkout conversion in E1. |
|
||||
| E2 | Evidence administration, host CLI and pending activation recovery | 1,355 backend, 639 frontend, 1,248 harness; portable-path rerun passed with THT_HOME unset. Initial authenticated visual acceptance remained manual. |
|
||||
| E3 | Draft import, explicit source refresh and protected manual corrections | 1,359 backend, 641 frontend, 1,256 harness; 24 focused checks. Synthetic filesystem/HTTP/S3 behavior, not a live S3-account certification. |
|
||||
| X1 | Human-reviewed Memory/Evidence conflict correction and durable recovery | 1,264 harness + 9 portable; 1,366 backend, 645 frontend, 199 Pi gates; desktop/mobile widget probe and later real authenticated administration probe. |
|
||||
|
||||
X1's configured `zai/glm-5.3` probe used synthetic conflicting knowledge. It was not a full
|
||||
autonomous Pi-session certification or acceptance of PSD semantics. Later administration
|
||||
checks exercised real authentication and a disposable synthetic workspace, including persistence
|
||||
across backend restart. Existing PSD archive content was not rewritten by those probes.
|
||||
|
||||
## Current authorities and repeatable checks
|
||||
|
||||
- [Memory implementation and storage](../gestione-memory.md), ADR 0018.
|
||||
- [Editable Evidence](../contracts/curated-evidence-v4.md), ADR 0019.
|
||||
- [Session corrections](../contracts/archive-repair.md).
|
||||
- [Evidence lifecycle acceptance](../testing/evidence-lifecycle-test-plan.md).
|
||||
- Harness tests under `tests/memory/`, Evidence integration tests, backend route/service tests,
|
||||
Pi gate tests and frontend tests are the executable regression boundaries. Run portable-path
|
||||
tests without a THT_HOME override; optional L2/provider tests require separate authorization.
|
||||
|
||||
Do not equate passing synthetic tests with real-provider quality, live S3 coverage, PSD-domain
|
||||
acceptance or permission to migrate another installation. Those remain explicit operator gates.
|
||||
|
||||
## Catalog/model design records consolidated at the same time
|
||||
|
||||
The old metadata-catalog exploration and description-generation plan/spec are no longer
|
||||
current-state authorities. PostgreSQL/Fastify ownership, installation bindings, description
|
||||
generation and source-sampling constraints now live in ADRs 0001–0016,
|
||||
[architecture](../architecture/overview.md), [Database Management](../operations/database-management.md)
|
||||
and the [description acceptance checklist](../testing/2026-08-29-ai-catalog-description-generation-acceptance.md).
|
||||
The installation-model plan is replaced by ADR 0013 and the
|
||||
[current model catalog guide](../general/pi-configuration.md).
|
||||
|
||||
Preserve these outstanding questions rather than infer acceptance from implementation:
|
||||
real provider/DWH acceptance recorded by the owner, licensing review of shipped optional models,
|
||||
future dialect/multi-schema support, and any desired semantic aliases/value descriptions.
|
||||
The former proposed catalog-to-core cutover and separate database permissions are already
|
||||
represented by current ADR 0016 and `database.manage`; do not reopen them as unfinished steps.
|
||||
The original description-generation plan referred to issue #4 for final delivery gates;
|
||||
this consolidation neither changes nor closes its tracker state.
|
||||