feat: implement memory and evidence administration with guided repairs
Publish documentation / publish (push) Successful in 1m27s
Publish documentation / publish (push) Successful in 1m27s
Add PostgreSQL-backed memory, editable evidence with source review and activation, and human-approved archive repairs across the harness, API, and UI. Include migrations, deployment support, regression coverage, and validation documentation. Refresh permissions from validated session roles so existing administrator logins can access newly deployed archive management features.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# Session corrections to Memory and Evidence
|
||||
|
||||
`reviewer_archive_repair` presents one to five closed alternatives for a conflict.
|
||||
Each alternative updates one existing Memory Card or one existing local Evidence unit,
|
||||
showing complete current and resulting content. The reviewer chooses one alternative,
|
||||
rejects all as inadequate, or asks for reformulation. A correction does not approve or
|
||||
advance the session phase; the ordinary gate still reviews its use in the current question.
|
||||
|
||||
The harness coordinator `tht/archive_repair.py` joins two independent domains. It uses
|
||||
Memory's PostgreSQL repository, workspace mutation lock and projection service, and the
|
||||
same local Evidence save/consolidation boundary as administration. Evidence activation
|
||||
runs the existing corpus pipeline without reacquiring configured external sources.
|
||||
No database binding, schema configuration, other archive, or Git repository is changed.
|
||||
|
||||
## Authority and recovery
|
||||
|
||||
Migration `004_archive_repairs.sql` stores session-bound proposals and receipts in
|
||||
`thoth_memory.archive_repairs`, isolated by workspace RLS. Each receipt captures the
|
||||
session decision context, current target revision, complete resulting content, selected
|
||||
choice, acting principal and publication outcome. The preparation command changes no
|
||||
archive content. Application accepts only an option ID from the persisted proposal.
|
||||
|
||||
Memory writes its new revision and receipt in one SQL transaction. Projection failures
|
||||
leave a durable pending operation; retry propagates the saved revision. A later card
|
||||
edit invalidates replay of the correction.
|
||||
|
||||
Evidence records the exact choice before writing its canonical file. Recovery accepts
|
||||
either the reviewed original revision or the already-written approved result; it never
|
||||
overwrites a different intervening correction. Before a first proposal, the editable
|
||||
checkout must match its active snapshot. Other curated files are fingerprinted and
|
||||
checked again before application/retry so a session decision cannot publish unrelated
|
||||
external edits. A crash after replacement is recoverable by the same receipt. Original
|
||||
document provenance is retained as the lineage of the manual correction.
|
||||
|
||||
The gate displays these outcomes:
|
||||
|
||||
| Status | Meaning |
|
||||
| --- | --- |
|
||||
| `proposed` | Waiting for a human choice; no content saved |
|
||||
| `rejected` | All alternatives declined; reformulation required |
|
||||
| `applying` | Choice recorded; file write or candidate recovery still required |
|
||||
| `pending_activation` | Content saved; index activation incomplete |
|
||||
| `active` | Saved correction matches the currently active revision |
|
||||
| `superseded` | The target was removed or changed after the saved correction |
|
||||
|
||||
The reviewer may retry a pending correction or continue the current question while
|
||||
leaving activation explicitly pending. The latter is not persistent-resolution success.
|
||||
`repair-show` refreshes target status; `repairs` lists the historical receipt status.
|
||||
The final Memory summary must not create a duplicate of a correction already saved here.
|
||||
|
||||
## Authorization and commands
|
||||
|
||||
Inspection/preparation requires an accessible open session in the same workspace.
|
||||
Applying either archive correction requires an administrator. Browser responses are
|
||||
also checked against the responding principal's `memory.manage` or `evidence.manage`
|
||||
permission and the Pi runtime owner. An administrator using another principal's runtime
|
||||
must resume it under their own account first, preserving truthful receipt attribution.
|
||||
Non-administrators may reject proposals or continue question review without changing
|
||||
the archives. The Pi shell guard blocks `repair-apply`; only the human gate invokes it.
|
||||
|
||||
The Python workflow CLI provides `memory repair-target`, `repair-prepare`, `repair-show`,
|
||||
`repair-apply`, and `repairs`. These are workflow integration commands, not new native
|
||||
installation commands. All accept `--session` and command-local `-c`; JSON output remains
|
||||
machine-readable. Proposal bodies are bounded to 1 MB. Durable receipts support both
|
||||
filesystem and server session storage without a persisted chat transcript.
|
||||
@@ -0,0 +1,248 @@
|
||||
# Editable Curated Evidence v4
|
||||
|
||||
Curated unit v4 makes the visible Markdown body authoritative. It uses the existing
|
||||
typed Evidence payloads and stable identifiers. Workspace descriptor v4 and Evidence
|
||||
descriptor v1/v2 are separate version numbers.
|
||||
|
||||
E1 implements the format, explicit conversion, local archive and consolidation API.
|
||||
E2 connects that API to the installed consolidation command, Evidence management
|
||||
page and runtime source selection. The local PSD preview now uses 35 converted units.
|
||||
|
||||
## Write or edit a file
|
||||
|
||||
Place units in `<workspace-root>/evidence/curated/<kind>/<name>.md`. Keep the existing
|
||||
`id` when editing. The directory must match `kind`. A new manual unit needs no external
|
||||
document, hash or encoded metadata:
|
||||
|
||||
```markdown
|
||||
---
|
||||
schema_version: 4
|
||||
id: evidence:order-key
|
||||
kind: domain
|
||||
language: en
|
||||
purposes: [sql_generation]
|
||||
applies_to:
|
||||
tables: [sales.orders]
|
||||
---
|
||||
|
||||
# Order key
|
||||
|
||||
## Rule
|
||||
|
||||
Join orders using the order number, financial year and company.
|
||||
```
|
||||
|
||||
Required metadata is `schema_version`, `id`, `kind`, `language`, and a nonempty
|
||||
`purposes` list. Purposes are `disambiguation`, `rewriting`, `schema_linking`, and
|
||||
`sql_generation`. Optional `applies_to` contains `concepts`, `tables`, and `columns`.
|
||||
Tables use `schema.table`; columns use `schema.table.column`.
|
||||
|
||||
The first H1 is the title. H2 headings identify the payload fields below. Heading
|
||||
spelling follows `language`: Italian for `it` and its regional variants, English
|
||||
otherwise. Keep structural headings when editing the text below them.
|
||||
|
||||
| Kind | English field headings | Italian field headings |
|
||||
| --- | --- | --- |
|
||||
| `domain` | Rule | Regola |
|
||||
| `glossary` | Definition, Synonyms, Variants | Definizione, Sinonimi, Varianti |
|
||||
| `enum` | Column, Values | Colonna, Valori |
|
||||
| `example` | Question, Interpretation | Domanda, Interpretazione |
|
||||
| `mapping` | Concept, Tables, Columns | Concetto, Tabelle, Colonne |
|
||||
| `normalization` | Input, Output, Rule | Input, Output, Regola |
|
||||
| `formula` | Concept, Columns, SQL | Concetto, Colonne, SQL |
|
||||
| `reference` | URL, Label, Description | URL, Etichetta, Descrizione |
|
||||
|
||||
List fields use one `- value` per line. Empty optional lists may be omitted. Quoted
|
||||
JSON strings within bullets preserve unusual or multiline values during conversion.
|
||||
Enum values use `### "stored value"`, followed by their meaning; `### ""` represents
|
||||
an empty stored value. Formula SQL uses a fenced `sql` block containing one PostgreSQL
|
||||
expression. Whole queries and mutation statements remain invalid.
|
||||
|
||||
Nested prose headings and fenced examples are supported inside text fields. An H2
|
||||
matching a field heading is structural outside a code fence. Duplicate fields, missing
|
||||
required fields, duplicate metadata keys and malformed payloads are rejected. There
|
||||
is no second title or payload in frontmatter and no hidden authoritative rule text.
|
||||
Conversion fails explicitly if a legacy payload cannot be represented losslessly.
|
||||
|
||||
## Current provenance and original source
|
||||
|
||||
The host supplies document provenance when refining source material: relative source
|
||||
path, normalized source hash and exact supporting excerpts. A manual unit can omit
|
||||
`provenance`. Consolidation records `kind: manual` and the supplied curator identity.
|
||||
|
||||
A visible change to a previously recorded unit becomes a manual declaration. If that
|
||||
unit originated from a document, its former document provenance is retained under
|
||||
`original`. The original excerpts establish lineage; they do not assert that the
|
||||
source contains the new wording. Retrieval carries this distinction through typed
|
||||
metadata. Curators edit content; the service updates managed provenance.
|
||||
|
||||
Unchanged document declarations still require matching source bytes and excerpts.
|
||||
Replacing a source requires an explicit refresh through the E3 source-review path. Ordinary preparation
|
||||
is blocked on an initialized local archive, preventing regenerated source material
|
||||
from overwriting corrections or restoring deletions. Legacy `resolve` is likewise
|
||||
blocked there; local file corrections and the archive API own those changes.
|
||||
|
||||
## Persistent archive and activation
|
||||
|
||||
```text
|
||||
<workspace-root>/
|
||||
.evidence-archive.lock
|
||||
evidence/
|
||||
source/ # acquired original documents
|
||||
curated/<kind>/*.md # editable primary content
|
||||
local-manifest.yaml # derived declarations and deletion records
|
||||
.local/
|
||||
state.yaml # baseline, pending and active revisions
|
||||
snapshots/<revision>/ # immutable units, source bytes and manifest
|
||||
```
|
||||
|
||||
Keep the complete Evidence tree and its managed metadata in backups and the operator's
|
||||
Git review. Historical source bytes and deletion records are needed to preserve manual
|
||||
care across subsequent imports. The separate corpus cache and Qdrant index are derived.
|
||||
The lock file only coordinates local service operations.
|
||||
|
||||
`LocalEvidenceArchive.initialize()` records the pre-edit baseline without activation.
|
||||
`consolidate(actor=..., activate=...)` validates files, derives provenance, records
|
||||
deletions and source suppression, and creates an immutable candidate. The activation
|
||||
callback receives that snapshot and must raise if indexing is blocked or fails. Only
|
||||
successful activation advances `active_snapshot()`. Without a callback the result is
|
||||
explicitly `pending_activation`; saving a file alone never changes this pointer.
|
||||
|
||||
The same candidate can be retried after an index failure. Interrupted managed writes
|
||||
are replayed only when the operator's file bytes have not changed. A missing curated
|
||||
directory is an availability error, not proof that all units were deleted. Removing
|
||||
unit files from an accessible directory records deletion without deleting their sources.
|
||||
The API also provides `get`, revision-checked `save`, and revision-checked `remove` for
|
||||
future deliberate workflow corrections. Concurrent external edits produce conflicts.
|
||||
|
||||
These boundaries are exercised with the existing corpus pipeline and real Qdrant.
|
||||
An initialized installation reads only its active local snapshot, including during
|
||||
ordinary preprocessing. Unconsolidated edits are visible in Administration but do
|
||||
not enter retrieval. Before initialization, the pinned repository source still works.
|
||||
|
||||
## Administration and installed command
|
||||
|
||||
Open **Administration → Evidence management**. This independent page requires the
|
||||
`evidence.manage` permission and no active session. It shows complete units, source
|
||||
lineage, review items, file errors, filters, and changes relative to the active snapshot.
|
||||
Edit the displayed Markdown path using an external editor. Refresh files to inspect
|
||||
the result, then run the command shown by the page:
|
||||
|
||||
```sh
|
||||
tht --installation /absolute/path/thothii-installation.yaml \
|
||||
workspace evidence consolidate --workspace psd-clinical
|
||||
```
|
||||
|
||||
The installed command accepts `--json`. It validates and activates Evidence using
|
||||
the existing corpus pipeline and embedding service. It does not scan the DWH, run
|
||||
full workspace preprocessing, change Catalog/Schema readiness, or execute Git.
|
||||
If indexing fails after saving, the archive retains the candidate for retry and the
|
||||
previous active revision remains selected. Validation errors identify corrections
|
||||
to make in the files. Structural and review checks still apply; initialized archives
|
||||
do not require the legacy repository's fixed retrieval-evaluation fixture, whose
|
||||
expected IDs would otherwise prevent deliberate local deletions.
|
||||
|
||||
The canonical workspace root is `<workspace-registry-root>/repo/<workspace-id>`.
|
||||
Snapshots and the derived corpus are separate. For a registry in a Docker volume,
|
||||
copy its existing `repo` to a persistent host directory before enabling
|
||||
`deploy/compose.evidence-host.yaml`; set `THT_EVIDENCE_HOST_REGISTRY_ROOT` to that
|
||||
directory and include the override in the installation descriptor. Core and
|
||||
workspace-maintenance must mount the same checkout. Keep registry state/snapshots
|
||||
on their existing volume. The page only presents a host path when configured; it
|
||||
does not label an internal container path as a usable editor path.
|
||||
|
||||
After successful consolidation, inspect and commit the complete workspace Evidence
|
||||
tree, including managed manifests, snapshots, and deletion records, then push manually.
|
||||
The page provides quoted POSIX-shell examples for status, diff, add, commit, and push.
|
||||
Do not commit only the edited Markdown. Ordinary Git operations remain the operator's
|
||||
responsibility. E3 source decisions use this same activation boundary.
|
||||
|
||||
**Clear** removes derived Reference/corpus data while retaining editable files,
|
||||
snapshots and Memory. It still requires full workspace preprocessing to recreate
|
||||
Reference/Schema readiness; Evidence consolidation does not satisfy that gate.
|
||||
|
||||
## Import drafts and refresh sources
|
||||
|
||||
Place externally authored Markdown drafts in `<workspace-root>/evidence/incoming/`.
|
||||
The specialist needs no installation account or database access to write a draft.
|
||||
Copying the draft to the installation and choosing **Import or refresh sources** in
|
||||
Evidence management explicitly starts acquisition and refinement. The equivalent
|
||||
installed command is:
|
||||
|
||||
```sh
|
||||
tht --installation /absolute/path/thothii-installation.yaml \
|
||||
workspace evidence refresh --workspace psd-clinical
|
||||
```
|
||||
|
||||
This reads local `incoming/**/*.md` and original `source/**/*.md` files, excluding
|
||||
managed `source/acquired/` versions. It also reads configured HTTP and S3 sources
|
||||
through the existing read-only adapters and network policies. After local archive
|
||||
initialization, filesystem descriptors use this local authoring tree; ordinary
|
||||
runtime/preprocessing never fetches remote source changes. No source-server write
|
||||
credential is needed. The existing Pi authoring refiner runs once for each changed
|
||||
document, without session state or tools. Unchanged source hashes skip refinement.
|
||||
|
||||
All acquisitions and proposals must succeed before the new comparison set is
|
||||
recorded. An access or refinement failure preserves previous comparisons and active
|
||||
Evidence. A source absent from a successful discovery is marked missing and never
|
||||
treated as permission to delete units. Restore an accidentally missing local original
|
||||
file before consolidating its document-derived units, or explicitly retire those units.
|
||||
|
||||
Each changed source has a durable comparison showing current local units, complete
|
||||
proposed content, supporting excerpts, and IDs that replacement would retire:
|
||||
|
||||
- **Keep local Evidence** retains the current wording as a manual declaration, with
|
||||
its original documentary lineage preserved. The changed source is acknowledged;
|
||||
the next unchanged refresh does not reopen that decision.
|
||||
- **Use proposed Evidence** adopts the displayed proposal and explicitly retires the
|
||||
displayed omitted IDs. The source version and provenance change together.
|
||||
|
||||
Both choices save and activate through the same local consolidation/index pipeline.
|
||||
Review items block adoption; correct the original draft and refresh, or keep local
|
||||
content. There is no automatic merge based on a model's semantic conflict assessment.
|
||||
Any change to an affected curated file invalidates the comparison and requires a new
|
||||
refresh. If indexing fails after the decision is saved, use **Retry saved decision**;
|
||||
this reuses acquired content without fetching sources again. An intervening external
|
||||
edit is never silently overwritten by recovery.
|
||||
|
||||
Headless operators can make the same decision using the source ID and comparison
|
||||
revision from the local source registry or administration response:
|
||||
|
||||
```sh
|
||||
tht --installation /absolute/path/thothii-installation.yaml \
|
||||
workspace evidence decide --workspace psd-clinical \
|
||||
--source-id <64-hex-source-id> --revision <64-hex-comparison-revision> \
|
||||
--decision keep
|
||||
```
|
||||
|
||||
Use `--decision replace` to adopt the proposal. All installed commands accept `--json`.
|
||||
The Python `evidence sources` worker is internal to this installed command/API surface.
|
||||
|
||||
`evidence/.local/sources.json` stores source identities, comparisons and retry journals.
|
||||
`evidence/.local/acquisitions/` preserves original acquired bytes and credential-free
|
||||
remote provenance. Adopted normalized documents live under
|
||||
`evidence/source/acquired/<source-id>/<content-hash>.md`. Versioned paths let a new
|
||||
document and an older manual declaration's original source coexist. Include all of
|
||||
these files in the existing manual Git/backup sequence. Do not edit managed acquired
|
||||
versions: edit the original local draft or refresh its remote origin.
|
||||
|
||||
Deleted IDs remain reserved. Once a source has had a curated deletion, fresh model
|
||||
IDs from that source are conservatively suppressed as well: changing an ID must not
|
||||
restore retired knowledge. Existing surviving IDs can still receive reviewed updates;
|
||||
deliberate new knowledge can be written as a manual Evidence file. Refresh is bounded
|
||||
to 200 documents and 100 MiB per operation, in addition to each adapter's limits.
|
||||
|
||||
## Convert an existing workspace
|
||||
|
||||
The existing workflow CLI command `tht evidence migrate <workspace-root>` converts
|
||||
unit versions 1–3 to 4 deterministically and initializes the archive baseline. It
|
||||
preserves IDs, typed content, provenance and review items, with no model call or Git
|
||||
commit. It does not activate a local index. Review items still block consolidation.
|
||||
The command's existing Git-worktree path check remains in effect.
|
||||
|
||||
The first installed consolidation performs this conversion automatically when the
|
||||
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).
|
||||
@@ -6,8 +6,9 @@ When present, `evidence` is strict: it contains `source` and a defaulted strict
|
||||
source variant and the policy reject unknown keys.
|
||||
|
||||
The version numbers are intentionally separate: the Evidence descriptor supports v1/v2, while the
|
||||
latest Curated Evidence Unit format is v3. There is no Evidence descriptor v3/v4 and no Curated
|
||||
Evidence Unit v4.
|
||||
latest Curated Evidence Unit format is [v4](curated-evidence-v4.md). There is no Evidence
|
||||
descriptor v3/v4. The editable local archive is implemented in E1; installation integration
|
||||
is the next increment, E2.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -67,9 +68,11 @@ ignore it. Domain rules also retain their exact canonical text in an invisible `
|
||||
comment while presenting long prose as paragraphs, labelled subsections, and semicolon-derived
|
||||
lists. Runtime chunking reads the parsed canonical rule, not this review-only presentation.
|
||||
|
||||
Newly prepared units use v3. `tht evidence migrate <workspace-root>` upgrades v1 and v2 units and
|
||||
canonicalizes an older v3 presentation locally without a model call, commit, publication, or
|
||||
semantic change.
|
||||
The representations above are legacy conversion inputs. Newly prepared units use editable v4:
|
||||
short YAML metadata, a visible H1 title and typed H2 payload fields, with no hidden content copy.
|
||||
`tht evidence migrate <workspace-root>` converts v1–v3 to v4 and initializes a local archive
|
||||
baseline without a model call, commit, activation, or semantic change. See the
|
||||
[v4 editing and consolidation contract](curated-evidence-v4.md).
|
||||
|
||||
### Example: filesystem
|
||||
|
||||
|
||||
@@ -14,12 +14,30 @@ tht --installation <absolute>/thothii-installation.yaml workspace preprocess run
|
||||
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace preprocess clear
|
||||
--workspace <id> [--json]
|
||||
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace evidence consolidate
|
||||
--workspace <id> [--json]
|
||||
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace evidence refresh
|
||||
--workspace <id> [--json]
|
||||
|
||||
tht --installation <absolute>/thothii-installation.yaml workspace evidence decide
|
||||
--workspace <id> --source-id <64-hex> --revision <64-hex>
|
||||
--decision keep|replace [--json]
|
||||
```
|
||||
|
||||
There are no public partial commands for DWH introspection, LSH, FK suggestions, schema indexing,
|
||||
Evidence indexing, or Qdrant rebuild. `preprocess run` does not accept `--resume`, `--dry-run`, a
|
||||
or Qdrant rebuild. The separate Evidence curation command validates editable local files and
|
||||
activates only their index; it does not satisfy workspace preprocessing readiness or execute Git.
|
||||
See [Curated Evidence v4](curated-evidence-v4.md#administration-and-installed-command).
|
||||
Source refresh acquires and refines only on explicit request, saving comparisons without
|
||||
changing active Evidence. Source decisions activate through the same Evidence-only
|
||||
pipeline and preserve Catalog readiness. Their envelopes reject arbitrary URLs, paths
|
||||
and extra flags; source locations and credentials come from installation configuration.
|
||||
`preprocess run` does not accept `--resume`, `--dry-run`, a
|
||||
generation identifier, or a rollback option. Re-running it replaces the preceding derived output.
|
||||
`preprocess clear` removes all replaceable preprocessing output and preserves runtime memory.
|
||||
`preprocess clear` removes all replaceable preprocessing output and preserves runtime memory
|
||||
and the canonical local Evidence archive. Full preprocessing remains required afterward.
|
||||
|
||||
## Sources of truth
|
||||
|
||||
@@ -29,8 +47,10 @@ generation identifier, or a rollback option. Re-running it replaces the precedin
|
||||
- PostgreSQL Metadata Catalog is the sole database authority. It owns the workspace/database
|
||||
association, installation-local binding, tables, columns, descriptions, sensitivity flags,
|
||||
physical foreign keys, and active logical relationships.
|
||||
- The workspace Git revision remains authoritative for Evidence. Evidence Descriptor v1/v2 and
|
||||
Curated Evidence Unit v3 are unchanged; there is no Evidence v4.
|
||||
- Evidence Descriptor v1/v2 still configures the initial source. Initialized archives use
|
||||
editable Curated Evidence Unit v4 and the last successfully activated local snapshot.
|
||||
Ordinary preprocessing never imports unconsolidated working-tree edits. Before initialization,
|
||||
the pinned workspace Git source remains supported.
|
||||
|
||||
No metadata is imported from legacy workspace YAML or `physical.yaml`/`annotations.yaml`.
|
||||
|
||||
@@ -98,9 +118,8 @@ generation produced for another database or revision.
|
||||
|
||||
`workspace preprocess clear` is intentionally narrower than deleting all semantic data. It:
|
||||
|
||||
1. copies any `memory` and `solved_question` records still present in the pre-split workspace
|
||||
collection to `<workspace>-memory`, then retires that legacy collection (a normal preprocessing
|
||||
write performs the same one-time cutover if clear was not invoked first);
|
||||
1. leaves `<workspace>-memory` unchanged; Memory projections are reconstructed only from
|
||||
the authoritative PostgreSQL archive, never imported from legacy vector payloads;
|
||||
2. deletes `<workspace>-reference`;
|
||||
3. removes the active LSH generation, Evidence corpus, private Catalog snapshot, and derived job
|
||||
checkpoints;
|
||||
|
||||
Reference in New Issue
Block a user