AI proposals and the export check
An AI result is a Typed block that the model wrote. Two things tell that a block still waits for a person: the block has a Derivation made by the model, and nobody has changed or checked it since. The editor derives both facts on every read. Nothing new is stored: the decision of a person is the Prüfung (a record pinned to a content hash), and the status is the derived Freigabestatus.
vorgeschlagen
A block is an AI proposal when all of these hold (isAiProposal(editor, node), @skaile/forge-editor/composites):
- its Derivation names the model as author:
methodstarts withai:(asderiveandcomposite-fillwrite it), oractivity.agentis set; outputHashis not empty and equals the SHA-256 of the block's body Markdown now, so nobody has edited the body since the model wrote it.
The Freigabestatus of a block, per kind, gains one value:
| Per kind | Meaning |
|---|---|
geprueft | a record of this kind exists at the current hash |
veraltet | records of this kind exist, none at the current hash |
vorgeschlagen | no record of this kind, and the block is an AI proposal |
offen | no record of this kind, and the block is not an AI proposal |
The order of the cases is fixed: a record decides first. An edit of the body ends the proposal, so the kind reads offen, not vorgeschlagen: the person who edits has taken the text over, and the Prüfung that follows pins their version. A block that is vorgeschlagen counts as open in freigabeOf: the document is freigegeben only after every such block has a Prüfung.
Where it shows:
| Where | What |
|---|---|
| Chip after the title | „KI-Vorschlag“ (warning) while a kind is vorgeschlagen and none is veraltet; „Prüfung veraltet“ and „Geprüft“ keep their rules |
| Section „Prüfstand“ | the kind line reads „KI-Vorschlag“ |
Only blocks whose Block type lists the pruefung capability have a Freigabestatus. PruefungKindStatus is 'geprueft' | 'veraltet' | 'offen' | 'vorgeschlagen'; a host that switches over it adds the case.
The export check
Before a Typed block is exported as Markdown the editor looks for what a reader of the file could trip over. exportIssuesOf(editor, node) (@skaile/forge-editor/composites) returns one ExportIssue per finding, for node and every Typed block inside it, in document order:
interface ExportIssue {
/** The Typed block the finding concerns (for a reference chip, the block that holds the chip). */
blockId: string
code: 'ai-unchecked' | 'stale-derived' | 'source-missing' | 'unresolved-reference'
/** Title of that block. */
title: string
}
| Code | When | Label |
|---|---|---|
ai-unchecked | the block is an AI proposal and still waits for a Prüfung (see the check probe below) | „KI-Vorschlag ungeprüft“ |
stale-derived | the block is Derived and its original changed since it was made | „Quelle geändert“ |
source-missing | the block is Derived and its original is gone | „Quelle fehlt“ |
unresolved-reference | a reference chip points at a Block that does not exist | „Verweis ohne Ziel“ |
The check hashes and serialises bodies. It runs when someone exports or opens the inspector section, not for every row.
The export never waits
The block action „Als Markdown exportieren“ (document-export) runs the check first. With one or more findings it shows a warning notice („1 Hinweis“, „n Hinweise“) that points at the inspector, and it exports anyway. The check informs, it never blocks.
The inspector section
The composites bindings add the section „Export-Hinweise“ (id export-check) to the Typed block inspector and the details card, for every Block type that lists the export capability. It lists the findings with their label and the block title, or „Keine Hinweise“. It follows document changes and Prüfung records. ExportCheckSection is exported from @skaile/forge-editor/composites/vue and @skaile/forge-editor/composites/react. A host that builds compositeFeatureCore itself passes the component as CompositesUi.exportCheck; without it the Feature adds no section (the notice stays).
Who tells that a block is checked
ai-unchecked needs to know whether a Prüfung exists, and the composites Feature does not know the pruefung Feature. A Feature that records checks provides a check probe for its editor:
import { provideCheckProbe } from '@skaile/forge-editor/composites'
const unprovide = provideCheckProbe(editor, {
// true while the block still waits for a check
awaitsCheck: (_editor, node) => !myChecks.has(node.attrs.id),
// optional: the answer changed without a document change (the inspector section draws again)
subscribe: listener => myChecks.subscribe(listener),
})
The pruefung Feature does this for its model: a block awaits a check while any configured kind is not geprueft. A block whose Block type has no kind awaits nothing, so it is never listed as ai-unchecked. Without any probe every AI proposal is ai-unchecked. provideCheckProbe returns the function that removes the probe; call it when the editor goes away.
Citations
Cite a bibliography entry of the Document with the inline cite node: insert it with /zitat, read it as (Autor Jahr), and keep it through Markdown export and import.
Query: filter, sort, group and total Blocks
The DataQuery model, its pseudo-fields and operators per property kind, the evaluator, the BlockIndex.query port method, the route, the client call and the find_blocks tool.