update
@@ -1,8 +1,23 @@
|
||||
"""Anbindung an MiniMax über das Anthropic-Messages-Format. Kein Fallback: fehlt die
|
||||
Konfiguration oder antwortet der Provider nicht, bricht der Aufruf mit sichtbarer
|
||||
Meldung ab."""
|
||||
"""Zwei Wege zum Modell, je nach Aufgabe.
|
||||
|
||||
`frage` geht über MiniMax im Anthropic-Messages-Format: die Prüfungen sind hundert
|
||||
Anfragen je Lauf und leben von der Temperaturstreuung — das muss billig und
|
||||
parallelisierbar sein.
|
||||
|
||||
`frage_lokal` geht über die angemeldete Claude-CLI, dasselbe Abo wie die
|
||||
Agenten-Übergabe. Die Gespräche sind einzelne Aufrufe und leben von Urteilskraft;
|
||||
dort zählt Qualität, nicht Durchsatz.
|
||||
|
||||
Welche Werkzeuge dabei offenstehen, entscheidet die Betriebsart, nicht das Modell:
|
||||
Planung liest den Projektcode, Recherche sucht im Web, und keine der beiden kann,
|
||||
was die andere darf. Die Prüfungen bekommen gar nichts — dort ist der Katalog die
|
||||
einzige zulässige Quelle.
|
||||
|
||||
Kein Fallback zwischen beiden: fehlt ein Weg, bricht der Aufruf mit sichtbarer
|
||||
Meldung ab, statt still auf das schwächere Modell auszuweichen."""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -12,6 +27,73 @@ ZEITLIMIT = 180.0
|
||||
MAX_TOKENS = 8000
|
||||
API_VERSION = "2023-06-01"
|
||||
|
||||
GRUNDLAGE = (
|
||||
"claude", "-p", "--model", "opus", "--output-format", "json",
|
||||
# Spart ein Fünftel der Grundlast; was hier gilt, steht ohnehin im eigenen Prompt.
|
||||
"--exclude-dynamic-system-prompt-sections",
|
||||
# Ohne das erbt der Aufruf, was am Rechner sonst eingerichtet ist: MCP-Server,
|
||||
# Workflows, Hooks, ein fremder Antwortstil. Ein Gespräch über Feature-Karten hat
|
||||
# in keinem Postfach etwas zu suchen.
|
||||
"--safe-mode",
|
||||
)
|
||||
|
||||
# Was in keiner Betriebsart erlaubt ist. Beide Gespräche holen fremden Text in den
|
||||
# Kontext — das eine Suchtreffer, das andere Quelltext — und fremder Text darf keinen
|
||||
# Terminplan anlegen, keine Nachricht verschicken und keine Agenten starten. Was
|
||||
# künftig an Werkzeugen dazukommt, steht hier nicht: beim Nachziehen der CLI gehört
|
||||
# diese Liste geprüft.
|
||||
GESPERRT = (
|
||||
"Write", "Edit", "NotebookEdit", "Bash", "Task", "TodoWrite",
|
||||
"Workflow", "Skill", "ReportFindings", "ScheduleWakeup", "DesignSync",
|
||||
"CronCreate", "CronDelete", "CronList", "RemoteTrigger", "PushNotification",
|
||||
"SendMessage", "Monitor", "EnterWorktree", "ExitWorktree",
|
||||
"TaskCreate", "TaskGet", "TaskList", "TaskOutput", "TaskStop", "TaskUpdate",
|
||||
)
|
||||
|
||||
|
||||
def _kommando(erlaubt: tuple, gesperrt: tuple, zuege: int) -> tuple:
|
||||
"""Ein Aufruf mit genau den Werkzeugen einer Betriebsart.
|
||||
|
||||
`--allowed-tools` ist nicht bloß die Umkehrung von `--disallowed-tools`: ohne die
|
||||
Vorabfreigabe fragt die CLI je Suche und je Datei nach Erlaubnis und bekommt im
|
||||
Stapelbetrieb keine Antwort. Der Versuch endet dann als Absage, nicht als Fehler.
|
||||
|
||||
`ToolSearch` steht nirgends: Suche, Abruf und Lesen sind nachladbar, ohne das
|
||||
Werkzeug käme das Modell gar nicht an sie heran. Was es nachlädt, ist trotzdem
|
||||
gesperrt — die Sperre wirkt beim Aufruf, nicht beim Suchen.
|
||||
"""
|
||||
return (*GRUNDLAGE,
|
||||
"--allowed-tools", *erlaubt,
|
||||
"--disallowed-tools", *GESPERRT, *gesperrt,
|
||||
"--max-turns", str(zuege))
|
||||
|
||||
|
||||
# Planen heißt: an den Karten arbeiten, mit dem Code als Beleg. Das Web bleibt zu —
|
||||
# was das Projekt können soll, entscheidet die Person, nicht eine fremde Seite.
|
||||
PLANUNG_KOMMANDO = _kommando(
|
||||
("Read", "Glob", "Grep"), ("WebSearch", "WebFetch"), 20)
|
||||
# Ohne eingestelltes Arbeitsverzeichnis gibt es nichts zu lesen. Lesen bliebe hier
|
||||
# nicht folgenlos: ohne gesetzten Ordner liefe die Suche im Serververzeichnis, und
|
||||
# das Modell beschriebe planer2 statt des Projekts.
|
||||
PLANUNG_OHNE_CODE = _kommando(
|
||||
(), ("Read", "Glob", "Grep", "WebSearch", "WebFetch"), 1)
|
||||
# Recherche geht nach draußen und nirgendwo sonst: kein Blick in Dateien, damit
|
||||
# nichts aus dem Projekt in einer Suchanfrage landet.
|
||||
RECHERCHE_KOMMANDO = _kommando(
|
||||
("WebSearch", "WebFetch"), ("Read", "Glob", "Grep"), 24)
|
||||
|
||||
# Opus denkt länger als MiniMax, der Prozessstart kostet extra, und Suchen wie
|
||||
# Codelesen legen mehrere Abrufe obendrauf.
|
||||
CHAT_ZEITLIMIT = 600.0
|
||||
|
||||
# Nur fürs Log: welcher Weg gerade lief. Ohne den Namen sagt eine Zeitangabe nichts,
|
||||
# denn dieselbe Sekundenzahl ist bei einem Zug teuer und bei zwanzig billig.
|
||||
WEGE = {
|
||||
PLANUNG_KOMMANDO: "planung+code",
|
||||
PLANUNG_OHNE_CODE: "planung",
|
||||
RECHERCHE_KOMMANDO: "recherche",
|
||||
}
|
||||
|
||||
# Der Provider drosselt bei vielen gleichzeitigen Anfragen
|
||||
WIEDERHOLBAR = (429, 500, 502, 503, 504)
|
||||
WIEDERHOLUNGEN = 6
|
||||
@@ -39,6 +121,67 @@ def pruefe_konfiguration():
|
||||
raise NichtKonfiguriert(f"Nicht konfiguriert: {', '.join(fehlend)} in .env fehlt")
|
||||
|
||||
|
||||
async def frage_lokal(system: str, inhalt: str,
|
||||
kommando: tuple = PLANUNG_OHNE_CODE,
|
||||
ordner: str | None = None) -> str:
|
||||
"""Eine Runde über die Claude-CLI — der Text der Antwort.
|
||||
|
||||
Der Prompt geht über die Standardeingabe: Katalog und Kartenstand sind zu lang,
|
||||
um sie als Kommandozeilenargument zu übergeben. Keine Temperatur — die CLI kennt
|
||||
keine; für einen einzelnen Zug braucht es auch keine Streuung.
|
||||
|
||||
`ordner` ist das Verzeichnis, in dem der Aufruf läuft. Es entscheidet, was ein
|
||||
erlaubtes Lesen erreicht; ohne Angabe erbt der Prozess das Serververzeichnis, und
|
||||
das ist nur zulässig, solange gar nicht gelesen werden darf.
|
||||
"""
|
||||
try:
|
||||
prozess = await asyncio.create_subprocess_exec(
|
||||
*kommando, "--system-prompt", system,
|
||||
cwd=ordner,
|
||||
stdin=asyncio.subprocess.PIPE,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
raise NichtKonfiguriert(
|
||||
"Claude-CLI nicht gefunden — „claude“ muss im Pfad liegen und angemeldet sein"
|
||||
)
|
||||
try:
|
||||
aus, err = await asyncio.wait_for(
|
||||
prozess.communicate(inhalt.encode()), CHAT_ZEITLIMIT)
|
||||
except asyncio.TimeoutError:
|
||||
prozess.kill()
|
||||
raise RuntimeError(f"Claude antwortet nicht innerhalb von {CHAT_ZEITLIMIT:.0f} s")
|
||||
if prozess.returncode != 0:
|
||||
raise RuntimeError(f"Claude bricht ab: {err.decode()[-300:].strip() or 'ohne Meldung'}")
|
||||
try:
|
||||
daten = json.loads(aus)
|
||||
except ValueError:
|
||||
raise RuntimeError("Antwort der Claude-CLI ist kein JSON")
|
||||
if daten.get("is_error"):
|
||||
raise RuntimeError(f"Claude meldet einen Fehler: {daten.get('result')}")
|
||||
_notiere(kommando, daten)
|
||||
text = str(daten.get("result") or "")
|
||||
if not text.strip():
|
||||
raise RuntimeError("Leere Antwort von Claude")
|
||||
return text
|
||||
|
||||
|
||||
def _notiere(kommando: tuple, daten: dict):
|
||||
"""Wohin die Wartezeit ging — ins Serverlog, eine Zeile je Aufruf.
|
||||
|
||||
Die CLI legt es ohnehin bei; ungelesen bleibt nur die Frage „wieso dauert das so
|
||||
lange" offen. Ein Zug ist ein Modellaufruf: jede Suche, jeder Abruf, jedes Lesen
|
||||
zählt einzeln. Sind die Züge hoch, hat das Modell gearbeitet; ist einer teuer, war
|
||||
der Prompt lang.
|
||||
"""
|
||||
zuege = daten.get("num_turns") or 0
|
||||
api = (daten.get("duration_api_ms") or 0) / 1000
|
||||
print(f"[claude] {WEGE.get(kommando, 'aufruf')}: {api:.0f}s, {zuege} Züge, "
|
||||
f"{(api / zuege if zuege else api):.0f}s/Zug, "
|
||||
f"${daten.get('total_cost_usd') or 0:.3f}", flush=True)
|
||||
|
||||
|
||||
def _pause(res, versuch: int) -> float:
|
||||
"""Wie lange bis zum nächsten Versuch — der Provider darf es selbst sagen."""
|
||||
gesagt = res.headers.get("retry-after")
|
||||
|
||||
319
backend/auftrag.py
Normal file
@@ -0,0 +1,319 @@
|
||||
"""Die Planung an einen Agenten übergeben.
|
||||
|
||||
Claude implementiert die geplanten Änderungen im Arbeitsverzeichnis — lokal über
|
||||
die Claude-CLI mit dem angemeldeten Konto. Solange er arbeitet, bleibt die
|
||||
Planung stehen: die Übersicht sagt, was das Projekt kann, und das stimmt erst,
|
||||
wenn der Code da ist. Erst nach Erfolg wird die Planung übernommen. Ein
|
||||
Fehlschlag übernimmt nichts; die Planung steht noch und kann erneut los.
|
||||
|
||||
Der Agent meldet jeden erledigten Schritt als eigene Zeile; der Server liest den
|
||||
Stream mit und hakt die Schritte ab. Zustand nur im Speicher — er überlebt keinen
|
||||
Serverneustart, der laufende Prozess arbeitet trotzdem zu Ende, übernimmt dann
|
||||
aber nichts mehr sichtbar.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import difflib
|
||||
import json
|
||||
import re
|
||||
|
||||
import parser
|
||||
import planung
|
||||
import projekte
|
||||
import verzeichnis
|
||||
|
||||
# stream-json liefert je Zeile ein Ereignis: sichtbar wird, woran der Agent
|
||||
# gerade arbeitet, und die ERLEDIGT-Zeilen kommen an, sobald sie fallen.
|
||||
KOMMANDO = ("claude", "-p", "--model", "opus", "--permission-mode", "acceptEdits",
|
||||
"--output-format", "stream-json", "--verbose")
|
||||
MARKE = "ERLEDIGT:"
|
||||
# Einzelne Stream-Zeilen tragen ganze Dateien — die Standardgrenze ist zu klein
|
||||
PUFFER = 10 * 1024 * 1024
|
||||
|
||||
# projektname -> {"laeuft", "fehler", "text", "schritte", "aktivitaet", "uebernommen"}
|
||||
_laeufe = {}
|
||||
_aufgaben = set()
|
||||
|
||||
PRUEFEN = "PRÜFEN"
|
||||
# Eine neue Funktion ist immer unbewiesen — es gibt noch keinen Code, der sie leistet.
|
||||
ART = {"weg": "GESTRICHEN", "geaendert": "GEÄNDERT", "neu": PRUEFEN}
|
||||
|
||||
AUFTRAG = """Du bekommst die Feature-Karten eines Projekts und die geplanten Änderungen.
|
||||
Eine Karte ist ein Auftrag: Regeln sind Zusicherungen, eine Funktion ist etwas,
|
||||
das man für sich testen kann. Setze den Code in diesem Verzeichnis so um, dass er
|
||||
den geänderten Karten entspricht.
|
||||
|
||||
- Lies zuerst den bestehenden Code und folge seinen Konventionen.
|
||||
- Ändere nur, was die Arbeitsschritte verlangen.
|
||||
- {pruefen} heißt: die Funktion gilt als unbewiesen. Prüfe, ob der Code genau das
|
||||
leistet, was ihre Testschritte beschreiben. Fehlt sie, baue sie. Weicht sie ab,
|
||||
bring sie in Ordnung. Sie kann schon einmal gebaut worden sein und trotzdem falsch
|
||||
arbeiten — glaube dem Code nicht, weil er existiert.
|
||||
- GEÄNDERT heißt: gebaut, aber die Karte sagt jetzt etwas anderes.
|
||||
- GESTRICHEN heißt: die Fähigkeit wird entfernt.
|
||||
- Ein Kommando in Anführungszeichen muss danach genau so aufrufbar sein.
|
||||
- Führe vorhandene Tests aus, wenn es welche gibt.
|
||||
|
||||
Die Arbeitsschritte:
|
||||
|
||||
{schritte}
|
||||
|
||||
Gib nach jedem abgeschlossenen Schritt sofort eine eigene Textzeile aus,
|
||||
mit dem Schritt wörtlich wie oben:
|
||||
{marke} <Schritt>
|
||||
|
||||
Hake nur ab, was du geprüft hast. Konntest du einen Ablauf nicht ausführen — weil
|
||||
kein Fenster, kein Gerät oder kein Dienst da ist — dann melde ihn NICHT als erledigt.
|
||||
Schreib am Ende in einer eigenen Zeile, was du nicht prüfen konntest und warum.
|
||||
|
||||
Die betroffenen Karten, wie sie danach gelten:
|
||||
|
||||
{karten}"""
|
||||
|
||||
|
||||
def _kartentexte(projekt: str, titel: set) -> str:
|
||||
"""Der volle Text der geplanten Karten — der Sollzustand, nicht der Diff."""
|
||||
texte = []
|
||||
for datei in sorted(projekte.wurzel(projekt).glob("*.md")):
|
||||
roh = datei.read_text()
|
||||
if parser.zerlege(roh)["titel"] in titel:
|
||||
texte.append(roh.strip())
|
||||
return "\n\n=====\n\n".join(texte) or "(keine — nur Streichungen)"
|
||||
|
||||
|
||||
def _offene(projekt: str) -> set:
|
||||
"""(Karte, Funktion) für alles, was noch nicht bewiesen ist.
|
||||
|
||||
Auch in Karten, die sich gegenüber dem Stand nicht geändert haben: eine Funktion
|
||||
zurück auf „offen“ zu setzen ist die Art, eine kaputte Umsetzung zu melden. Sie
|
||||
muss dann in die Arbeitsliste, sonst hätte der Klick keine Folge.
|
||||
"""
|
||||
raus = set()
|
||||
for datei in projekte.wurzel(projekt).glob("*.md"):
|
||||
s = parser.zerlege(datei.read_text())
|
||||
if s["art"] == parser.VISION:
|
||||
continue
|
||||
for f in s["funktionen"]:
|
||||
if f["stand"] == parser.OFFEN:
|
||||
raus.add((s["titel"], f["text"]))
|
||||
return raus
|
||||
|
||||
|
||||
def _schritte(projekt: str, aenderungen: dict) -> list[dict]:
|
||||
"""Die Arbeitsliste: ein Eintrag je Streichung, Kopfänderung und Funktion.
|
||||
|
||||
Karte und Funktion stehen daneben, nicht nur im Text. Beim Abhaken wird die
|
||||
Funktion auf „gebaut“ gesetzt — den Namen aus dem Satz zurückzuparsen wäre
|
||||
eine zweite Wahrheit über dieselbe Sache.
|
||||
"""
|
||||
offen = _offene(projekt)
|
||||
raus = []
|
||||
erledigt = set()
|
||||
|
||||
def funktionsschritt(titel: str, name: str, art: str):
|
||||
erledigt.add((titel, name))
|
||||
# Offen schlägt geändert: „prüfen und herstellen“ deckt beides ab, und der
|
||||
# Agent soll dem vorhandenen Code nicht glauben.
|
||||
marke = PRUEFEN if (titel, name) in offen else ART[art]
|
||||
raus.append({"text": f"{titel} / {name}: {marke}", "karte": titel,
|
||||
# Eine gestrichene Funktion gibt es hinterher nicht mehr
|
||||
"funktion": "" if art == "weg" else name})
|
||||
|
||||
for titel in sorted(aenderungen):
|
||||
e = aenderungen[titel]
|
||||
if e["art"] == "weg":
|
||||
raus.append({"text": f"Karte „{titel}“ streichen",
|
||||
"karte": titel, "funktion": ""})
|
||||
erledigt |= {(titel, n) for n in e.get("funktionen", {})}
|
||||
continue
|
||||
if e.get("kopf"):
|
||||
raus.append({"text": f"Karte „{titel}“: Kartenkopf anpassen",
|
||||
"karte": titel, "funktion": ""})
|
||||
for name, art in sorted(e.get("funktionen", {}).items()):
|
||||
funktionsschritt(titel, name, art)
|
||||
|
||||
for titel, name in sorted(offen - erledigt):
|
||||
funktionsschritt(titel, name, "geaendert")
|
||||
return raus
|
||||
|
||||
|
||||
def _visionen(projekt: str) -> set:
|
||||
"""Titel der Vision-Karten, in Stand und Arbeitskopie."""
|
||||
titel = set()
|
||||
for ordner in (projekte.stand(projekt), projekte.wurzel(projekt)):
|
||||
for datei in ordner.glob("*.md"):
|
||||
s = parser.zerlege(datei.read_text())
|
||||
if s["art"] == parser.VISION:
|
||||
titel.add(s["titel"])
|
||||
return titel
|
||||
|
||||
|
||||
def bau_auftrag(projekt: str) -> tuple[str, list[dict]]:
|
||||
"""Prompt und Arbeitsliste, aus dem Stand der laufenden Planung.
|
||||
|
||||
Die Vision bleibt außen vor: sie beschreibt Absicht, keinen Auftrag —
|
||||
eine geänderte Vision ist nichts, was ein Agent bauen soll.
|
||||
"""
|
||||
if not planung.laeuft(projekt):
|
||||
return "", []
|
||||
visionen = _visionen(projekt)
|
||||
aenderungen = {t: e for t, e in planung.aenderungen(projekt).items()
|
||||
if t not in visionen}
|
||||
schritte = _schritte(projekt, aenderungen)
|
||||
if not schritte:
|
||||
return "", []
|
||||
# Der Sollzustand jeder Karte, die Arbeit trägt — auch der unveränderten mit
|
||||
# einer offenen Funktion. Ohne ihren Text wüsste der Agent nicht, wogegen er prüft.
|
||||
bleibend = {s["karte"] for s in schritte if s["karte"] not in {
|
||||
t for t, e in aenderungen.items() if e["art"] == "weg"}}
|
||||
text = AUFTRAG.format(
|
||||
schritte="\n".join(f'- {s["text"]}' for s in schritte),
|
||||
marke=MARKE,
|
||||
pruefen=PRUEFEN,
|
||||
karten=_kartentexte(projekt, bleibend))
|
||||
return text, schritte
|
||||
|
||||
|
||||
def status(projekt: str) -> dict:
|
||||
return _laeufe.get(projekt) or {
|
||||
"laeuft": False, "fehler": "", "text": "",
|
||||
"schritte": [], "aktivitaet": "", "uebernommen": False,
|
||||
}
|
||||
|
||||
|
||||
# „offen“ steht als eigener Block in der Datei; fehlt er, gilt die Funktion als
|
||||
# gebaut. Umstellen heißt darum: den Block streichen. Ein Umbau über den Parser
|
||||
# würde die Datei neu schreiben und dabei unbekannte Blöcke verlieren.
|
||||
_FUNKTIONSMARKE = re.compile(r"^<!--\s*funktion\s*-->[ \t]*$", re.M | re.I)
|
||||
_OFFENBLOCK = re.compile(
|
||||
r"^<!--\s*stand\s*-->[ \t]*\n[ \t]*" + parser.OFFEN + r"[ \t]*\n", re.M | re.I)
|
||||
|
||||
|
||||
def _als_gebaut(roh: str, funktion: str) -> str:
|
||||
"""Streicht den offen-Vermerk genau dieser Funktion."""
|
||||
marken = [m.start() for m in _FUNKTIONSMARKE.finditer(roh)]
|
||||
for i, start in enumerate(marken):
|
||||
ende = marken[i + 1] if i + 1 < len(marken) else len(roh)
|
||||
block = roh[start:ende]
|
||||
zeilen = [z.strip() for z in block.splitlines()[1:] if z.strip()]
|
||||
titel = next((z for z in zeilen
|
||||
if not z.startswith("<!--") and not z.startswith("---")), "")
|
||||
if titel != funktion:
|
||||
continue
|
||||
return roh[:start] + _OFFENBLOCK.sub("", block, count=1) + roh[ende:]
|
||||
return roh
|
||||
|
||||
|
||||
def _setze_gebaut(projekt: str, schritt: dict):
|
||||
"""Ein abgehakter Schritt heißt: der Code ist da, die Funktion ist gebaut.
|
||||
|
||||
Geschrieben wird in die Arbeitskopie; `planung.setze_um` trägt sie danach in den
|
||||
Projektstand. Scheitert der Agent später, bleibt der Haken stehen — was gebaut
|
||||
ist, ist gebaut, und die Planung läuft von dort weiter.
|
||||
"""
|
||||
if not schritt.get("funktion"):
|
||||
return
|
||||
for datei in projekte.wurzel(projekt).glob("*.md"):
|
||||
roh = datei.read_text()
|
||||
if parser.zerlege(roh)["titel"] != schritt.get("karte"):
|
||||
continue
|
||||
neu = _als_gebaut(roh, schritt["funktion"])
|
||||
if neu != roh:
|
||||
datei.write_text(neu)
|
||||
return
|
||||
|
||||
|
||||
def _hake_ab(projekt: str, lauf: dict, zeile: str):
|
||||
"""Eine ERLEDIGT-Zeile gegen die offenen Schritte halten.
|
||||
|
||||
Wörtlich wäre schön, aber ein Modell zitiert nicht immer wörtlich —
|
||||
deshalb genügt große Ähnlichkeit mit genau einem offenen Schritt.
|
||||
"""
|
||||
gemeldet = zeile.split(MARKE, 1)[1].strip()
|
||||
offen = [s for s in lauf["schritte"] if not s["fertig"]]
|
||||
for s in offen:
|
||||
if s["text"] == gemeldet:
|
||||
s["fertig"] = True
|
||||
_setze_gebaut(projekt, s)
|
||||
return
|
||||
naechster = max(
|
||||
offen,
|
||||
key=lambda s: difflib.SequenceMatcher(None, s["text"], gemeldet).ratio(),
|
||||
default=None)
|
||||
if naechster and difflib.SequenceMatcher(
|
||||
None, naechster["text"], gemeldet).ratio() >= 0.6:
|
||||
naechster["fertig"] = True
|
||||
_setze_gebaut(projekt, naechster)
|
||||
|
||||
|
||||
def _verarbeite(projekt: str, lauf: dict, roh: bytes):
|
||||
"""Ein Stream-Ereignis: Haken setzen, Aktivität zeigen, Ergebnis merken."""
|
||||
try:
|
||||
ereignis = json.loads(roh)
|
||||
except ValueError:
|
||||
return
|
||||
if ereignis.get("type") == "result":
|
||||
lauf["text"] = str(ereignis.get("result") or "").strip()
|
||||
return
|
||||
if ereignis.get("type") != "assistant":
|
||||
return
|
||||
for block in (ereignis.get("message") or {}).get("content") or []:
|
||||
if block.get("type") == "text":
|
||||
for zeile in str(block.get("text") or "").splitlines():
|
||||
if MARKE in zeile:
|
||||
_hake_ab(projekt, lauf, zeile)
|
||||
elif block.get("type") == "tool_use":
|
||||
eingabe = block.get("input") or {}
|
||||
ziel = (eingabe.get("file_path") or eingabe.get("path")
|
||||
or eingabe.get("command") or eingabe.get("pattern") or "")
|
||||
lauf["aktivitaet"] = f'{block.get("name", "")} {str(ziel)[:80]}'.strip()
|
||||
|
||||
|
||||
async def _fuehre_aus(projekt: str, auftrag: str, ordner: str):
|
||||
lauf = _laeufe[projekt]
|
||||
try:
|
||||
prozess = await asyncio.create_subprocess_exec(
|
||||
*KOMMANDO, cwd=ordner, limit=PUFFER,
|
||||
stdin=asyncio.subprocess.PIPE,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE)
|
||||
prozess.stdin.write(auftrag.encode())
|
||||
await prozess.stdin.drain()
|
||||
prozess.stdin.close()
|
||||
while zeile := await prozess.stdout.readline():
|
||||
_verarbeite(projekt, lauf, zeile)
|
||||
fehler = (await prozess.stderr.read()).decode(errors="replace").strip()
|
||||
if await prozess.wait() != 0:
|
||||
lauf["fehler"] = fehler or f"Agent endete mit Code {prozess.returncode}"
|
||||
return
|
||||
# Erst jetzt wird die Planung wahr: der Code entspricht den Karten.
|
||||
planung.setze_um(projekt)
|
||||
lauf["uebernommen"] = True
|
||||
except FileNotFoundError:
|
||||
lauf["fehler"] = "claude-CLI nicht gefunden — ist Claude Code installiert?"
|
||||
except Exception as e: # sichtbar statt still verschluckt
|
||||
lauf["fehler"] = str(e)
|
||||
finally:
|
||||
lauf["aktivitaet"] = ""
|
||||
lauf["laeuft"] = False
|
||||
|
||||
|
||||
def starte(projekt: str, auftrag: str, schritte: list[dict]) -> bool:
|
||||
"""Startet den Agenten im Hintergrund. False, wenn nichts zu tun ist."""
|
||||
if not auftrag:
|
||||
return False
|
||||
ordner = verzeichnis.lies(projekt)
|
||||
if not ordner:
|
||||
return False
|
||||
if status(projekt)["laeuft"]:
|
||||
raise ValueError("Für dieses Projekt arbeitet schon ein Agent")
|
||||
_laeufe[projekt] = {
|
||||
"laeuft": True, "fehler": "", "text": "",
|
||||
"schritte": [{**s, "fertig": False} for s in schritte],
|
||||
"aktivitaet": "", "uebernommen": False,
|
||||
}
|
||||
aufgabe = asyncio.get_event_loop().create_task(
|
||||
_fuehre_aus(projekt, auftrag, ordner))
|
||||
_aufgaben.add(aufgabe)
|
||||
aufgabe.add_done_callback(_aufgaben.discard)
|
||||
return True
|
||||
101
backend/chat.py
@@ -11,6 +11,15 @@ funktioniert, Annehmen schreibt die Datei.
|
||||
Das Modell schreibt nie selbst in eine Datei. Es beschreibt den Sollzustand einer
|
||||
Karte; was sich dadurch ändert, rechnet der Code aus. Das ist dieselbe Beweislast wie
|
||||
bei der Prüfung und der Grund, warum ein Missverständnis hier nichts kaputt macht.
|
||||
|
||||
Gefragt wird über die Claude-CLI, nicht über MiniMax: das Gespräch soll planen helfen.
|
||||
Ein Modell, das nur Kataloge abarbeitet, gibt hier die Frage zurück statt Vorschläge.
|
||||
|
||||
Zum Planen gehört der Quelltext, nicht das Web. Wer eine Karte entwirft, muss wissen,
|
||||
was heute schon dasteht — das steht im Arbeitsverzeichnis und nirgends sonst. Fremdes
|
||||
Wissen kommt aus der Recherche und ist ein eigener Raum (`recherche.py`): was dort
|
||||
gefunden wird, bringt die Person selbst mit, statt dass es unbemerkt in einen Entwurf
|
||||
sickert.
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -20,20 +29,28 @@ import features
|
||||
import parser
|
||||
import projekte
|
||||
import pruefung
|
||||
import verzeichnis
|
||||
|
||||
DATEI = ".chat.json"
|
||||
# So viele Wortmeldungen bleiben stehen. Mehr wäre teuer je Anfrage und hilft wenig:
|
||||
# was vor zwanzig Schritten besprochen wurde, steht längst auf den Karten.
|
||||
TIEFE = 30
|
||||
# Antworten in einem Rutsch. Ein Gespräch verträgt keine sechs Stimmen — es soll
|
||||
# schnell sein, und was falsch ist, sieht man am Vorschlag.
|
||||
TEMPERATUR = 0.3
|
||||
# schnell sein, und was falsch ist, sieht man am Vorschlag. Dafür das starke Modell:
|
||||
# hier wird geplant, nicht ein Katalog abgearbeitet.
|
||||
|
||||
SYSTEM = """Du entwickelst mit einer Person zusammen die Feature-Karten eines Projekts.
|
||||
|
||||
Eine Karte ist ein Auftrag: die Person will ein Problem gelöst haben. Die Lösung
|
||||
besteht aus Regeln und Funktionen. Eine Funktion ist etwas, das man für sich testen
|
||||
kann. Was nur die Umsetzung betrifft, gehört auf keine Karte.
|
||||
kann. Wie eine Sache gebaut ist, gehört auf keine Karte — wie man sie bedient, immer.
|
||||
|
||||
Bedienung ist nicht nur Maus und Menü. Einrichten, Installieren und Starten sind
|
||||
Funktionen wie jede andere; ihr Auslöser ist ein Kommando. Setze es wörtlich in
|
||||
Anführungszeichen, damit die Person es abtippen kann: `Befehl "make install"
|
||||
ausführen`. Was das Kommando innen tut, bleibt draußen.
|
||||
|
||||
{code}
|
||||
|
||||
{stil}
|
||||
|
||||
@@ -53,16 +70,55 @@ Antworte ausschließlich mit JSON:
|
||||
VOLLSTÄNDIG, so wie sie danach aussehen sollen. Der Stand oben hat dieselbe Form:
|
||||
kopiere die Karte von dort und ändere nur, was sich ändern soll. Jede Zeile, die
|
||||
du nicht wörtlich mit abschreibst, gilt als gestrichen.
|
||||
- art: „kern", wenn die Anwendung ohne die Karte keinen Sinn hätte, sonst „optional"
|
||||
- ziel, regeln und testen dürfen leer sein oder fehlen
|
||||
- art: „kern", wenn die Anwendung ohne die Karte nicht laufen kann, sonst „optional"
|
||||
- ziel und regeln dürfen leer sein oder fehlen
|
||||
- testen ist Pflicht bei jeder Funktion: der Ablauf, an dem man sie prüft. Weißt du
|
||||
ihn nicht, gehört die Funktion nicht auf die Karte — dann frag danach
|
||||
|
||||
Ist nichts zu ändern, ist karten leer. Ändere nur, wonach gefragt wurde; Karten,
|
||||
die niemand erwähnt hat, lässt du weg.
|
||||
|
||||
Frag nach, was du nicht weißt — aber leg trotzdem einen Entwurf daneben. Eine Frage
|
||||
ohne Vorschlag hilft niemandem: an einem Entwurf sieht die Person sofort, was du
|
||||
falsch verstanden hast. Erfinde dabei nichts, was nicht gesagt wurde; lass eine
|
||||
Funktion lieber knapp als ausgedacht."""
|
||||
Zwei Arten von Wortmeldung, und sie werden verschieden behandelt.
|
||||
|
||||
Eine Frage will eine Antwort, keinen Entwurf. „Wie ist das heute?", „Muss ich noch
|
||||
etwas tun?", „Wozu dient das?" — antworte in Prosa und lass karten leer. Ungefragt
|
||||
eine Karte anzufassen ist ein Fehler, auch wenn dir dabei etwas auffällt. Sag es in
|
||||
einem Satz und frag, ob du es aufnehmen sollst.
|
||||
|
||||
Ein Wunsch will einen Entwurf. Sobald etwas anders werden soll oder dazukommen soll,
|
||||
leg die Karten daneben, wie sie danach aussehen. Fehlt dir dafür eine Angabe, frag
|
||||
danach — aber leg trotzdem einen Entwurf daneben. An einem Entwurf sieht die Person
|
||||
sofort, was du falsch verstanden hast, und er gilt erst, wenn sie ihn annimmt.
|
||||
|
||||
Bei einem Wunsch gibst du die Frage nie unbeantwortet zurück. Wer nach Namen fragt
|
||||
— für Kommandos, Funktionen oder Karten — bekommt konkrete Namen, keine Gegenfrage.
|
||||
Nenne das Übliche für diese Art von Anwendung, sag in einem Satz, worauf du dich
|
||||
stützt, und frag danach, was daran nicht passt. „Das kann ich nicht vorschlagen" ist
|
||||
keine zulässige Antwort.
|
||||
|
||||
Gehört etwas nicht auf eine Karte, sag in einem Satz, wohin es stattdessen gehört.
|
||||
|
||||
Beim Bestand bleibst du bei der Wahrheit: über das, was das Projekt heute kann,
|
||||
erfindest du nichts. Ein Entwurf für etwas Neues kommt von dir."""
|
||||
|
||||
# Zwei Fassungen desselben Absatzes. Ohne eingestelltes Arbeitsverzeichnis gibt es
|
||||
# nichts zu lesen, und ein Angebot, das ins Leere greift, wäre schlimmer als keines:
|
||||
# das Modell behauptete sonst, nachgesehen zu haben.
|
||||
CODE_MIT = """Der Quelltext des Projekts liegt in deinem Arbeitsverzeichnis. Du darfst
|
||||
darin lesen und suchen, und du sollst es tun, sobald dein Entwurf davon abhängt, wie
|
||||
etwas heute gebaut ist: ob es eine Funktion schon gibt, wie eine Bedienstelle heißt,
|
||||
was ein Ablauf wirklich auslöst. Rate nicht, sieh nach.
|
||||
|
||||
Was du dort findest, ist ein Beleg, kein Kartentext. Wie eine Sache gebaut ist, gehört
|
||||
auf keine Karte — dorthin kommt nur, was die Person davon merkt. Stützt du dich auf
|
||||
eine Stelle, nenne im Antwortsatz die Datei.
|
||||
|
||||
Widerspricht der Code den Karten, schreib die Karte nicht still um. Sag in einem Satz,
|
||||
was du gefunden hast, und frag, welche Seite gilt."""
|
||||
|
||||
CODE_OHNE = """Für dieses Projekt ist kein Arbeitsverzeichnis eingestellt. Du kannst
|
||||
den Quelltext also nicht ansehen. Was das Projekt heute kann, weißt du nur aus den
|
||||
Karten unten — behaupte nichts darüber hinaus."""
|
||||
|
||||
# Die Formatregel steht auch hier, nicht nur im System-Prompt. Bei langen Antworten
|
||||
# vergaß das Modell sie sonst und schrieb reinen Fließtext — die ganze Wortmeldung
|
||||
@@ -80,6 +136,14 @@ Schreibe sie noch einmal, ausschließlich als das JSON-Objekt aus der Vorgabe
|
||||
keine Einleitung, kein Nachsatz, keine Code-Zäune."""
|
||||
|
||||
|
||||
def _arbeitsordner(projekt: str) -> str | None:
|
||||
"""Wo der Quelltext liegt — oder nichts, wenn dort nichts zu holen ist."""
|
||||
try:
|
||||
return str(verzeichnis.pruefe(verzeichnis.lies(projekt)))
|
||||
except (ValueError, FileNotFoundError, OSError):
|
||||
return None
|
||||
|
||||
|
||||
def _pfad(projekt: str):
|
||||
return projekte.wurzel(projekt) / DATEI
|
||||
|
||||
@@ -239,9 +303,11 @@ def vorschlaege(projekt: str, karten: list) -> list:
|
||||
if bestand is None:
|
||||
# Neue Karte: es gibt keine Stelle, an der man ansetzen könnte —
|
||||
# deshalb ein eigener Vorschlag, der die ganze Datei mitbringt.
|
||||
# `sektionen` liegt daneben: nur am Titel lässt sich nicht entscheiden,
|
||||
# ob die Karte taugt. Zerlegt wird hier, damit es keinen zweiten Parser gibt.
|
||||
raus.append({"feld": "neue_karte", "original": "", "vorschlag": titel,
|
||||
"roh": text, "ganzes_feld": True, "feature": "",
|
||||
"funktion": "", "regel": "Aus dem Gespräch",
|
||||
"roh": text, "sektionen": neu, "ganzes_feld": True,
|
||||
"feature": "", "funktion": "", "regel": "Aus dem Gespräch",
|
||||
"problem": "Neue Karte"})
|
||||
continue
|
||||
grund = f"Aus dem Gespräch: {titel}"
|
||||
@@ -256,24 +322,29 @@ async def frage(projekt: str, text: str) -> dict:
|
||||
text = (text or "").strip()
|
||||
if not text:
|
||||
raise ValueError("Nachricht ist leer")
|
||||
agents.pruefe_konfiguration()
|
||||
|
||||
bisher = verlauf(projekt)
|
||||
gespraech = "\n\n".join(f'{"Person" if e["rolle"] == "person" else "Du"}: {e["text"]}'
|
||||
for e in bisher) or "Noch nichts besprochen."
|
||||
# Der Ordner entscheidet über beides zugleich: was im Prompt angeboten wird und
|
||||
# was die CLI überhaupt zulässt. Ein toter Pfad zählt wie keiner — der Prozess
|
||||
# ließe sich darin nicht einmal starten.
|
||||
ordner = _arbeitsordner(projekt)
|
||||
# Beide Kataloge: der Chat schreibt Karten UND Funktionen. Vorher kannte er nur
|
||||
# die Kartenregeln und erfand Funktionstitel wie „Galerie im Modal" — ein
|
||||
# Bereich statt einer Handlung, und die Prüfung merkte es erst hinterher.
|
||||
system = SYSTEM.format(
|
||||
code=CODE_MIT if ordner else CODE_OHNE,
|
||||
stil="\n\n".join(pruefung._stil_lesen(b) for b in pruefung.BEREICHE),
|
||||
karten=_kartenstand(projekt))
|
||||
nachricht = NACHRICHT.format(verlauf=gespraech, text=text)
|
||||
kommando = agents.PLANUNG_KOMMANDO if ordner else agents.PLANUNG_OHNE_CODE
|
||||
|
||||
# Ein Ausrutscher beim JSON kostet sonst die ganze Wortmeldung. Zweiter Versuch
|
||||
# mit etwas mehr Streuung; danach fliegt der Fehler nach oben und ist sichtbar.
|
||||
# Ein Ausrutscher beim JSON kostet sonst die ganze Wortmeldung. Danach fliegt der
|
||||
# Fehler nach oben und ist sichtbar.
|
||||
daten = None
|
||||
for versuch in range(3):
|
||||
antwort = await agents.frage(system, nachricht, TEMPERATUR + 0.1 * versuch)
|
||||
antwort = await agents.frage_lokal(system, nachricht, kommando, ordner)
|
||||
try:
|
||||
daten = pruefung._json_lesen(antwort)
|
||||
break
|
||||
|
||||
BIN
backend/chatui.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
@@ -27,12 +27,8 @@ MINIMAX_API_KEY = os.environ.get("MINIMAX_API_KEY", "")
|
||||
MINIMAX_MODELL = os.environ.get("MINIMAX_MODELL", "")
|
||||
MINIMAX_URL = os.environ.get("MINIMAX_URL", "")
|
||||
|
||||
# Das Gespräch darf woanders laufen als die Prüfungen. Es ist ein einzelner Aufruf
|
||||
# und lebt von Sprachgefühl; die Prüfungen sind hundert Stimmen und leben von der
|
||||
# Temperaturstreuung. Nicht gesetzt heißt: alles über MiniMax.
|
||||
CHAT_API_KEY = os.environ.get("CHAT_API_KEY", "")
|
||||
CHAT_MODELL = os.environ.get("CHAT_MODELL", "")
|
||||
CHAT_URL = os.environ.get("CHAT_URL", "https://api.anthropic.com/v1/messages")
|
||||
# Das Gespräch läuft nicht hierüber, sondern über die angemeldete Claude-CLI
|
||||
# (`agents.frage_lokal`) — dasselbe Abo wie die Agenten-Übergabe, kein zweiter Zugang.
|
||||
|
||||
|
||||
def _zahl(name: str, standard: int) -> int:
|
||||
|
||||
@@ -81,35 +81,9 @@ def speichern(projekt: str, id: str, roh: str) -> dict:
|
||||
titel = parser.zerlege(roh)["titel"]
|
||||
if not titel:
|
||||
raise ValueError("Titel fehlt")
|
||||
vorher = datei.read_text()
|
||||
datei.write_text(roh)
|
||||
neu = _folge_titel(datei, titel)
|
||||
# Ein neuer Titel benennt die Datei um. Der Rückschritt muss beides kennen:
|
||||
# die neue Datei fällt weg, die alte kommt mit ihrem alten Inhalt zurück.
|
||||
schritt = {datei.stem: vorher}
|
||||
if neu.stem != datei.stem:
|
||||
schritt[neu.stem] = None
|
||||
return _eintrag(neu)
|
||||
return _eintrag(_folge_titel(datei, titel))
|
||||
|
||||
|
||||
def loeschen(projekt: str, id: str):
|
||||
datei = _datei(projekt, id)
|
||||
titel = parser.zerlege(datei.read_text())["titel"] or id
|
||||
datei.unlink()
|
||||
|
||||
|
||||
def verschieben(projekt: str, id: str, ziel: str) -> dict:
|
||||
"""Ein Feature in ein anderes Projekt umhängen.
|
||||
|
||||
Kein Kopieren: die Datei wandert, damit es sie nur einmal gibt. Der Verlauf
|
||||
hält beide Seiten fest — sonst ließe sich der Schritt nicht zurücknehmen.
|
||||
"""
|
||||
if ziel == projekt:
|
||||
raise ValueError("Feature liegt schon in diesem Projekt")
|
||||
datei = _datei(projekt, id)
|
||||
roh = datei.read_text()
|
||||
titel = parser.zerlege(roh)["titel"] or id
|
||||
# Erst das Ziel auflösen: gibt es das Projekt nicht, ist noch nichts passiert
|
||||
neu = _frei(projekte.wurzel(ziel), _slug(titel))
|
||||
datei.rename(neu)
|
||||
return _eintrag(neu)
|
||||
_datei(projekt, id).unlink()
|
||||
|
||||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -20,12 +20,18 @@ import shutil
|
||||
|
||||
import parser
|
||||
import projekte
|
||||
import verzeichnis
|
||||
|
||||
# Was beim Vergleich zählt: der sichtbare Inhalt einer Funktion, nicht ihre Datei.
|
||||
# Wird eine Karte umbenannt, wandert ihre Datei — der Vergleich hinge sonst an
|
||||
# einem Dateinamen statt an dem, was dasteht.
|
||||
FELDER = ("ziel", "regeln", "testen", "stand")
|
||||
|
||||
# Dateien, die dem Projekt gehören und nicht der Planung. Sie überleben das
|
||||
# Umsetzen, auch wenn die Kopie sie nicht kennt. Das Gespräch und das
|
||||
# Urteilsgedächtnis stehen bewusst nicht hier: die gehören zum geplanten Stand.
|
||||
NUR_PROJEKT = (verzeichnis.DATEI,)
|
||||
|
||||
|
||||
def laeuft(projekt: str) -> bool:
|
||||
return (projekte.stand(projekt) / projekte.PLANUNG).is_dir()
|
||||
@@ -55,6 +61,11 @@ def setze_um(projekt: str):
|
||||
Erst die Kopie herausheben, dann den alten Stand räumen, dann die Kopie an
|
||||
seine Stelle. Ein Absturz mitten im Räumen ließe sonst ein Projekt ohne Karten
|
||||
zurück — und die Planung gleich mit.
|
||||
|
||||
Was dem Projekt gehört und nicht der Planung, bleibt stehen: das
|
||||
Arbeitsverzeichnis wurde vielleicht erst nach dem Planungsstart festgelegt und
|
||||
fehlt dann in der Kopie. Das Räumen hat es mitgenommen, und der nächste Lauf
|
||||
fand kein Verzeichnis mehr.
|
||||
"""
|
||||
kopie = _kopie(projekt)
|
||||
if not kopie.is_dir():
|
||||
@@ -64,6 +75,9 @@ def setze_um(projekt: str):
|
||||
shutil.rmtree(daneben, ignore_errors=True)
|
||||
kopie.rename(daneben)
|
||||
for eintrag in ordner.iterdir():
|
||||
if eintrag.name in NUR_PROJEKT and not (daneben / eintrag.name).exists():
|
||||
eintrag.rename(daneben / eintrag.name)
|
||||
continue
|
||||
shutil.rmtree(eintrag) if eintrag.is_dir() else eintrag.unlink()
|
||||
for eintrag in daneben.iterdir():
|
||||
eintrag.rename(ordner / eintrag.name)
|
||||
|
||||
@@ -510,7 +510,7 @@ async def _stil_aufgaben(projekt: str):
|
||||
stand = ledger.lade(projekt)
|
||||
stand["stil"] = ledger.behalte(stand["stil"], {_stilschluessel(a) for a in liste})
|
||||
return (liste,
|
||||
lambda a, _zaehl: _pruefe(stil, a, stand),
|
||||
lambda a: _pruefe(stil, a, stand),
|
||||
lambda: ledger.sichere(projekt, stand))
|
||||
|
||||
|
||||
@@ -523,17 +523,12 @@ async def _lauf(projekt: str, liste: list[dict], arbeite, abschluss=None):
|
||||
lauf = _laeufe[projekt]
|
||||
schranke = asyncio.Semaphore(config.PRUEFUNG_PARALLEL)
|
||||
|
||||
def zaehl():
|
||||
lauf["fertig"] += 1
|
||||
|
||||
async def eine(aufgabe):
|
||||
if aufgabe is None:
|
||||
return # Platzhalter: zählt der Sammellauf selbst hoch
|
||||
async with schranke:
|
||||
if _laeufe.get(projekt) is not lauf:
|
||||
return # verworfen (Panel geschlossen) — keine weitere Anfrage
|
||||
try:
|
||||
lauf["probleme"].extend(await arbeite(aufgabe, zaehl))
|
||||
lauf["probleme"].extend(await arbeite(aufgabe))
|
||||
except Exception as e:
|
||||
# Zählt trotzdem als erledigt, sonst hängt der Fortschritt.
|
||||
# Die Meldung nennt die Zahl, damit „100 %" nicht vollständig vortäuscht.
|
||||
@@ -541,8 +536,7 @@ async def _lauf(projekt: str, liste: list[dict], arbeite, abschluss=None):
|
||||
lauf["meldung"] = (
|
||||
f"{lauf['fehler']} von {lauf['gesamt']} Prüfungen fehlgeschlagen: {e}"
|
||||
)
|
||||
if aufgabe is not True:
|
||||
lauf["fertig"] += 1
|
||||
lauf["fertig"] += 1
|
||||
|
||||
try:
|
||||
await asyncio.gather(*(eine(a) for a in liste))
|
||||
|
||||
208
backend/recherche.py
Normal file
@@ -0,0 +1,208 @@
|
||||
"""Herausfinden, was gebaut werden soll — in mehreren Fäden nebeneinander.
|
||||
|
||||
Recherche ist kein Nachschlagewerk. Sie klärt, was draußen gilt, damit die Planung
|
||||
daneben Karten schneiden kann: Zahlen, Grenzen, Namen, Belege. Was keine Entscheidung
|
||||
trägt, gehört nicht in die Antwort.
|
||||
|
||||
Die Karten liegen dabei, aber nur zum Lesen. Ohne sie fragt man ins Leere — „welche
|
||||
Funktionen fehlen noch" ist ohne den Bestand nicht zu beantworten, und das Modell
|
||||
riete am Projekt vorbei. Vorschläge macht die Recherche trotzdem keine: sie schreibt
|
||||
Prosa, keine Kartenfelder. Was aus einem Fund folgt, entscheidet die Person nebenan.
|
||||
|
||||
Mehrere Fäden, weil Themen sich sonst gegenseitig verdrecken. „Wie geht Upload zu S3"
|
||||
und „welche Diagrammbibliothek" haben nichts miteinander zu tun; in einem Verlauf
|
||||
zieht das Modell den einen Kontext in die andere Antwort. Ein Faden ist ein Thema,
|
||||
und er bleibt stehen, bis ihn jemand schließt.
|
||||
|
||||
Die Antwort ist Markdown und wird als solches angezeigt. Kein JSON: hier wird nichts
|
||||
in Felder zerlegt und nichts gegengerechnet, also gäbe es auch nichts zu prüfen — ein
|
||||
Formatzwang kostete nur einen Aufruf mehr, wenn das Modell ihn verfehlt.
|
||||
|
||||
Die Fäden liegen im Projektstand, nicht in der Planungskopie: Nachgeschlagenes gilt
|
||||
unabhängig davon, ob gerade geplant wird, und überlebt einen Planungsabbruch.
|
||||
"""
|
||||
|
||||
import json
|
||||
import uuid
|
||||
|
||||
import agents
|
||||
import features
|
||||
import parser
|
||||
import projekte
|
||||
import verzeichnis
|
||||
|
||||
DATEI = ".recherche.json"
|
||||
# So viele Wortmeldungen behält ein Faden. Recherche geht in die Tiefe, deshalb mehr
|
||||
# als im Planungsgespräch — dort steht das Ergebnis auf den Karten, hier nur im Faden.
|
||||
TIEFE = 40
|
||||
# Länger wird kein Reitertext lesbar; die ganze Frage steht ohnehin im Faden.
|
||||
TITELLAENGE = 40
|
||||
|
||||
SYSTEM = """Du recherchierst für jemanden, der Software plant.
|
||||
|
||||
Was du herausfindest, wird eine Aufgabe für die Implementierung. Schreib deshalb so,
|
||||
dass jemand danach loslegen kann, ohne deine Suche zu wiederholen: Zahlen, Grenzen,
|
||||
Namen, Belege. Was keine Entscheidung trägt, lässt du weg — kein Hintergrund, keine
|
||||
Geschichte, keine Alternative, die du schon verworfen hast.
|
||||
|
||||
Schlag im Web nach. Antworte nicht aus dem Gedächtnis, wenn es um Versionen, Grenzen,
|
||||
Preise, Schnittstellen oder aktuelle Empfehlungen geht — da veraltet Wissen still.
|
||||
Belege mit Links. Widersprechen sich zwei Quellen, sag es, statt dich zu entscheiden.
|
||||
Findest du nichts, sag auch das — eine erfundene Zahl ist hier teurer als keine.
|
||||
|
||||
Antworte auf Deutsch, als Markdown. So ist eine Antwort gebaut:
|
||||
|
||||
Ein bis drei Sätze Prosa: was du gefunden hast und was daraus folgt.
|
||||
|
||||
## Festgelegt
|
||||
Je Zeile eine Aussage mit ihrer Zahl, ihrem Namen, ihrer Grenze. Fett, was eine
|
||||
Entscheidung ist. Keine Begründung — die steht oben in der Prosa.
|
||||
|
||||
## Offen
|
||||
Was noch jemand entscheiden muss, als Frage. Weglassen, wenn nichts offen ist.
|
||||
|
||||
## Quellen
|
||||
Je Zeile ein Link mit einem Halbsatz, wofür er steht.
|
||||
|
||||
Die Überschriften stehen nur da, wo sie etwas tragen. Auf eine Rückfrage antwortest du
|
||||
in zwei Sätzen ohne Struktur; hast du nichts gefunden, sagst du das in einem.
|
||||
|
||||
Die Karten des Projekts stehen unten. Sie sagen, was gebaut werden soll — lies sie,
|
||||
bevor du fragst, wovon die Rede ist. Wer wissen will, was noch fehlt, bekommt eine
|
||||
Antwort, die sich auf diese Karten bezieht, nicht auf ein Projekt im Allgemeinen.
|
||||
|
||||
Du änderst die Karten nicht und schlägst auch keine Formulierung dafür vor. Was aus
|
||||
deinem Fund folgt, entscheidet die Person nebenan. Den Quelltext siehst du nicht:
|
||||
Was heute schon gebaut ist, steht als „gebaut" oder „offen" an den Funktionen.
|
||||
|
||||
Die Karten:
|
||||
|
||||
{karten}"""
|
||||
|
||||
|
||||
def _punkte(text: str) -> list:
|
||||
return [z.strip("- ").strip() for z in (text or "").splitlines() if z.strip()]
|
||||
|
||||
|
||||
def _karten(projekt: str) -> str:
|
||||
"""Der Kartenstand für den Prompt — mit „gebaut"/„offen", ohne Testabläufe.
|
||||
|
||||
Das Planungsgespräch blendet den Stand aus: dort entscheidet ihn der Code, und
|
||||
ein Feld weniger ist ein Feld weniger zum Vergessen. Hier ist er das Wichtigste
|
||||
am Bestand — „was fehlt noch" hängt an nichts anderem.
|
||||
|
||||
Die Testabläufe bleiben draußen. Sie sagen, wie man etwas prüft, und das trägt
|
||||
keine Recherche; sie würden nur den Prompt füllen.
|
||||
"""
|
||||
vision, karten = "", []
|
||||
for f in features.liste(projekt):
|
||||
s = f["sektionen"]
|
||||
if s["art"] == parser.VISION:
|
||||
vision = s["ziel"]
|
||||
continue
|
||||
karten.append({
|
||||
"titel": s["titel"], "art": s["art"], "ziel": s["ziel"],
|
||||
"regeln": _punkte(s["regeln"]),
|
||||
"funktionen": [{"titel": x["text"], "stand": x["stand"],
|
||||
"ziel": x["ziel"], "regeln": _punkte(x["regeln"])}
|
||||
for x in s["funktionen"]],
|
||||
})
|
||||
text = json.dumps(karten, indent=1, ensure_ascii=False) if karten \
|
||||
else "Noch keine Karten."
|
||||
if vision:
|
||||
text = f"So ist das Projekt gedacht:\n\n{vision}\n\nDie Karten:\n\n{text}"
|
||||
return text
|
||||
|
||||
|
||||
def _pfad(projekt: str):
|
||||
return projekte.stand(projekt) / DATEI
|
||||
|
||||
|
||||
def _lade(projekt: str) -> list:
|
||||
# Der Pfad wird vor dem try geholt: „Projekt gibt es nicht" ist ein
|
||||
# FileNotFoundError und damit ein OSError. Im try gefangen, würde daraus ein
|
||||
# leeres Ergebnis statt einer 404.
|
||||
datei = _pfad(projekt)
|
||||
try:
|
||||
faeden = json.loads(datei.read_text())
|
||||
except (OSError, ValueError):
|
||||
return []
|
||||
return faeden if isinstance(faeden, list) else []
|
||||
|
||||
|
||||
def _sichere(projekt: str, faeden: list):
|
||||
ziel = _pfad(projekt)
|
||||
neben = ziel.with_suffix(".json.neu")
|
||||
neben.write_text(json.dumps(faeden, indent=1, ensure_ascii=False) + "\n")
|
||||
neben.replace(ziel)
|
||||
|
||||
|
||||
def _finde(faeden: list, id: str) -> dict:
|
||||
for f in faeden:
|
||||
if f.get("id") == id:
|
||||
return f
|
||||
raise FileNotFoundError("Diesen Faden gibt es nicht mehr")
|
||||
|
||||
|
||||
def liste(projekt: str) -> list:
|
||||
"""Alle Fäden mit ihrem Verlauf — das Panel zeigt Reiter und Inhalt zugleich."""
|
||||
return _lade(projekt)
|
||||
|
||||
|
||||
def anlegen(projekt: str) -> dict:
|
||||
"""Ein leerer Faden. Seinen Namen bekommt er von der ersten Frage."""
|
||||
faeden = _lade(projekt)
|
||||
faden = {"id": uuid.uuid4().hex[:8], "titel": "Neu", "verlauf": []}
|
||||
faeden.append(faden)
|
||||
_sichere(projekt, faeden)
|
||||
return faden
|
||||
|
||||
|
||||
def loeschen(projekt: str, id: str):
|
||||
faeden = _lade(projekt)
|
||||
_finde(faeden, id)
|
||||
_sichere(projekt, [f for f in faeden if f.get("id") != id])
|
||||
|
||||
|
||||
def _titel(text: str) -> str:
|
||||
text = " ".join(text.split())
|
||||
return text if len(text) <= TITELLAENGE else f"{text[:TITELLAENGE].rstrip()}…"
|
||||
|
||||
|
||||
async def frage(projekt: str, id: str, text: str) -> dict:
|
||||
"""Eine Runde in einem Faden — der Faden mit der neuen Antwort."""
|
||||
text = (text or "").strip()
|
||||
if not text:
|
||||
raise ValueError("Nachricht ist leer")
|
||||
faden = _finde(_lade(projekt), id)
|
||||
|
||||
gespraech = "\n\n".join(
|
||||
f'{"Person" if e["rolle"] == "person" else "Du"}: {e["text"]}'
|
||||
for e in faden["verlauf"]) or "Noch nichts besprochen."
|
||||
nachricht = f"Bisher:\n{gespraech}\n\nNeue Frage:\n{text}"
|
||||
|
||||
# Ohne eingestelltes Arbeitsverzeichnis läuft der Prozess dort, wo der Server
|
||||
# steht. Lesen ist ohnehin gesperrt; der Ordner sorgt nur dafür, dass ein
|
||||
# gefundener Umweg im Projekt landet und nicht in planer2.
|
||||
ordner = None
|
||||
try:
|
||||
ordner = str(verzeichnis.pruefe(verzeichnis.lies(projekt)))
|
||||
except (ValueError, FileNotFoundError, OSError):
|
||||
pass
|
||||
|
||||
antwort = (await agents.frage_lokal(
|
||||
SYSTEM.format(karten=_karten(projekt)), nachricht,
|
||||
agents.RECHERCHE_KOMMANDO, ordner)).strip()
|
||||
|
||||
# Erst jetzt neu laden: der Aufruf dauert Minuten, in denen ein anderer Faden
|
||||
# angelegt oder geschlossen worden sein kann. Der Faden selbst kann weg sein —
|
||||
# dann ist die Antwort verfallen, und das ist richtig so.
|
||||
faeden = _lade(projekt)
|
||||
faden = _finde(faeden, id)
|
||||
if not faden["verlauf"]:
|
||||
faden["titel"] = _titel(text)
|
||||
faden["verlauf"] += [{"rolle": "person", "text": text},
|
||||
{"rolle": "ki", "text": antwort}]
|
||||
faden["verlauf"] = faden["verlauf"][-TIEFE:]
|
||||
_sichere(projekt, faeden)
|
||||
return faden
|
||||
@@ -4,11 +4,14 @@ hier wird auf 400/404/409 gemappt."""
|
||||
from fastapi import APIRouter, HTTPException
|
||||
|
||||
import agents
|
||||
import auftrag
|
||||
import chat
|
||||
import features
|
||||
import projekte
|
||||
import planung
|
||||
import pruefung
|
||||
import recherche
|
||||
import verzeichnis
|
||||
|
||||
router = APIRouter(prefix="/api")
|
||||
|
||||
@@ -127,17 +130,64 @@ async def planung_starten(name: str):
|
||||
|
||||
@router.post("/projekte/{name}/planung/umsetzen")
|
||||
async def planung_umsetzen(name: str):
|
||||
"""Mit Arbeitsverzeichnis implementiert ein Agent die Änderungen; die Planung
|
||||
bleibt stehen und wird erst nach seinem Erfolg übernommen. Ohne Verzeichnis
|
||||
oder ohne Änderungen wird sofort übernommen."""
|
||||
try:
|
||||
planung.setze_um(name)
|
||||
anweisung, schritte = auftrag.bau_auftrag(name)
|
||||
agent = auftrag.starte(name, anweisung, schritte)
|
||||
if not agent:
|
||||
planung.setze_um(name)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
except ValueError as e:
|
||||
raise HTTPException(409, str(e))
|
||||
return {"ok": True}
|
||||
return {"ok": True, "agent": agent}
|
||||
|
||||
|
||||
@router.get("/projekte/{name}/auftrag")
|
||||
async def auftrag_status(name: str):
|
||||
return auftrag.status(name)
|
||||
|
||||
|
||||
@router.get("/system/ordner")
|
||||
async def ordner_liste(pfad: str = ""):
|
||||
"""Zum Durchblättern im Verzeichnis-Dialog — listet nur, schreibt nie."""
|
||||
try:
|
||||
return verzeichnis.ordner(pfad)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
except ValueError as e:
|
||||
raise HTTPException(400, str(e))
|
||||
|
||||
|
||||
@router.get("/projekte/{name}/verzeichnis")
|
||||
async def verzeichnis_lesen(name: str):
|
||||
try:
|
||||
return {"pfad": verzeichnis.lies(name)}
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
|
||||
|
||||
@router.put("/projekte/{name}/verzeichnis")
|
||||
async def verzeichnis_setzen(name: str, body: dict):
|
||||
pfad = (body.get("pfad") or "").strip()
|
||||
try:
|
||||
if not pfad:
|
||||
verzeichnis.loesche(name)
|
||||
return {"pfad": ""}
|
||||
return {"pfad": verzeichnis.setze(name, pfad)}
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
except ValueError as e:
|
||||
raise HTTPException(400, str(e))
|
||||
|
||||
|
||||
@router.delete("/projekte/{name}/planung")
|
||||
async def planung_abbrechen(name: str):
|
||||
# Solange der Agent auf der Planung arbeitet, darf sie ihm niemand wegziehen
|
||||
if auftrag.status(name)["laeuft"]:
|
||||
raise HTTPException(409, "Der Agent arbeitet noch an dieser Planung")
|
||||
try:
|
||||
planung.brich_ab(name)
|
||||
except FileNotFoundError as e:
|
||||
@@ -147,6 +197,8 @@ async def planung_abbrechen(name: str):
|
||||
|
||||
@router.post("/projekte/{name}/planung/zuruecksetzen")
|
||||
async def planung_zuruecksetzen(name: str, body: dict):
|
||||
if auftrag.status(name)["laeuft"]:
|
||||
raise HTTPException(409, "Der Agent arbeitet noch an dieser Planung")
|
||||
try:
|
||||
planung.zuruecksetzen(name, (body or {}).get("titel") or "")
|
||||
except FileNotFoundError as e:
|
||||
@@ -171,16 +223,6 @@ async def feature_loeschen(name: str, id: str):
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@router.put("/projekte/{name}/features/{id}/projekt")
|
||||
async def feature_verschieben(name: str, id: str, body: dict):
|
||||
try:
|
||||
return features.verschieben(name, id, (body.get("ziel") or "").strip())
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
except ValueError as e:
|
||||
raise HTTPException(400, str(e))
|
||||
|
||||
|
||||
@router.get("/projekte/{name}/chat")
|
||||
async def chat_verlauf(name: str):
|
||||
try:
|
||||
@@ -208,3 +250,40 @@ async def chat_leeren(name: str):
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@router.get("/projekte/{name}/recherche")
|
||||
async def recherche_faeden(name: str):
|
||||
try:
|
||||
return {"faeden": recherche.liste(name)}
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
|
||||
|
||||
@router.post("/projekte/{name}/recherche")
|
||||
async def recherche_anlegen(name: str):
|
||||
try:
|
||||
return recherche.anlegen(name)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
|
||||
|
||||
@router.post("/projekte/{name}/recherche/{id}")
|
||||
async def recherche_frage(name: str, id: str, body: dict):
|
||||
try:
|
||||
return await recherche.frage(name, id, body.get("text") or "")
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
except agents.NichtKonfiguriert as e:
|
||||
raise HTTPException(400, str(e))
|
||||
except ValueError as e:
|
||||
raise HTTPException(400, str(e))
|
||||
|
||||
|
||||
@router.delete("/projekte/{name}/recherche/{id}")
|
||||
async def recherche_loeschen(name: str, id: str):
|
||||
try:
|
||||
recherche.loeschen(name, id)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(404, str(e))
|
||||
return {"ok": True}
|
||||
|
||||
@@ -8,22 +8,42 @@ Abweichung als Problem und schlägt einen korrigierten Text vor.
|
||||
Gilt für jedes Feld.
|
||||
|
||||
- Sprache: Deutsch, Präsens, keine Anrede
|
||||
- Icons heißen `<Name>-Icon`. Der Name darf ein Zeichen sein: `x-Icon`, `+-Icon`,
|
||||
`Stift-Icon`. Ein Doppelpunkt mit dem tatsächlichen Zeichen dahinter ist erlaubt
|
||||
(`Nacht-Icon: ☾`)
|
||||
- Maustasten als `LMB`, `RMB`, `MMB`
|
||||
- Ein Menüeintrag wird wörtlich zitiert: `Klick auf "Feature entfernen"`
|
||||
- Ein Kommando wird wörtlich zitiert: `Befehl "make install" ausführen`
|
||||
- Ein Zitat zählt als ein Wort und darf Sonderzeichen tragen
|
||||
- Jeder Gegenstand heißt überall gleich
|
||||
|
||||
## Bedienung, nicht Bauweise
|
||||
|
||||
Karten beschreiben, was gilt und wie man es auslöst. Wie es aussieht und wie es
|
||||
innen gebaut ist, gehört nicht dazu.
|
||||
|
||||
- Keine Icons, keine Zeichen als Namen
|
||||
- Keine Farben
|
||||
- Keine Positionen wie `rechts oben` oder `unter dem Titel`
|
||||
- Kein Layout: Rahmen, Spalten, Abstände, Breiten
|
||||
- Erlaubt ist der Bereich: `Kopfzeile`, `Hauptbereich`, `Projektliste`
|
||||
- Kein Aufbau eines Skripts, nur sein Aufruf
|
||||
- Keine Dateinamen, Klassen oder Bibliotheken
|
||||
|
||||
Richtig: `LMB auf die Einstufung` · `Rückfrage vor dem Entfernen`
|
||||
Richtig: `Befehl "make install" ausführen` · `Ein Aufruf genügt`
|
||||
Falsch: `Augen-Icon rechts oben` · `Kern blau umrandet` · `Marke rechts vom Titel`
|
||||
Falsch: `Das Skript legt einen Symlink in autostart` (Bauweise)
|
||||
|
||||
## Vom System gemessen
|
||||
|
||||
Diese Vorgaben prüft der Code selbst, exakt und für jede Zeile. Halte dich beim
|
||||
Schreiben daran — aber berufe dich nie darauf. Als `regel` sind sie nicht zulässig.
|
||||
|
||||
- Jede Funktion hat Ziel, Regeln oder Testschritte — nie nur einen Titel
|
||||
- Jede Funktion hat Testschritte — ohne sie ist sie keine Funktion
|
||||
- Titel einer Funktion endet auf ein Verb im Infinitiv
|
||||
- Titel einer Funktion beginnt nicht mit einem Auslöser
|
||||
- Testschritte beschreiben genau einen Ablauf
|
||||
- Kein Satzzeichen am Zeilenende, kein Punkt und kein Semikolon
|
||||
- Keine Füllwörter. Die Liste ist abschließend: auch, noch, einfach, jeweils, ggf.
|
||||
- Keine Klammern und keine Schrägstriche
|
||||
- Keine Klammern und keine Schrägstriche außerhalb eines Zitats
|
||||
- Titel der Karte: höchstens 3 Wörter
|
||||
- Titel einer Funktion: höchstens 5 Wörter
|
||||
- Ziel: höchstens 2 Sätze, je höchstens 12 Wörter
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
Feld `badge`.
|
||||
|
||||
- `kern`: ohne die Karte ist das Projekt nicht benutzbar
|
||||
- `optional`: nützlich, aber verzichtbar
|
||||
- `kern`: fehlt die Karte, kann die Anwendung nicht laufen
|
||||
- `optional`: fehlt die Karte, läuft die Anwendung weiter — mit weniger Funktionen
|
||||
- Die Prüffrage ist immer dieselbe: Streiche die Karte. Läuft der Rest noch?
|
||||
- Die Einstufung muss zum Ziel der Karte passen
|
||||
- Im Zweifel `kern`
|
||||
|
||||
Richtig: `Projekte` ist kern · `Darkmode` ist optional
|
||||
Falsch: `Darkmode` als kern (das Projekt läuft ohne)
|
||||
Richtig: `Projekt` ist kern · `Prüfung` ist optional
|
||||
Falsch: `Prüfung` als kern (ohne Prüfung läuft der Planer weiter)
|
||||
Falsch: `Sicherung` als kern, weil sie wichtig ist (wichtig heißt nicht tragend)
|
||||
|
||||
@@ -4,10 +4,13 @@ Feld `regeln`, wenn `funktion` leer ist. Gilt für die ganze Karte.
|
||||
|
||||
- Eine Zeile je Regel
|
||||
- Genau eine Aussage je Zeile; zwei Aussagen werden zu zwei Regeln
|
||||
- Sichert etwas zu, das man sonst nicht sieht
|
||||
- Beschreibt eine Eigenschaft oder Bedingung, keinen Ablaufschritt
|
||||
- Steht nicht schon in den Testschritten
|
||||
- Steht nicht schon als Regel der Karte
|
||||
- Keine Aufzählung mit Komma oder „und" zweier gleichrangiger Aussagen
|
||||
- Ein Icon-Name allein ist eine gültige Regel
|
||||
|
||||
Richtig: `Alphabetisch sortiert` · `Verlassen speichert` · `Escape verwirft`
|
||||
Falsch: `Kern blau umrandet, Optional grün umrandet` (zwei Aussagen)
|
||||
Falsch: `Klick auf Badge` (Ablaufschritt, gehört zu Testen)
|
||||
Falsch: `Titel eingeben, dann bestätigen` (zwei Aussagen)
|
||||
Falsch: `LMB auf Badge` (Ablaufschritt, gehört zu Testen)
|
||||
Falsch: `Entsteht leer`, wenn die Testschritte keine Eingabe zeigen (schon sichtbar)
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
Feld `titel`, wenn `funktion` leer ist.
|
||||
|
||||
- Substantiv, oder Objekt mit Verb im Infinitiv
|
||||
- Benennt die Sache, kein ganzer Satz
|
||||
- Benennt einen Gegenstand, keine Tätigkeit
|
||||
- Sammelbegriff für die Funktionen der Karte
|
||||
- Jede Funktion der Karte handelt von diesem Gegenstand
|
||||
- Ein Wort, wenn es reicht
|
||||
|
||||
Richtig: `Features` · `Karten prüfen` · `Darkmode`
|
||||
Falsch: `Features verwalten und anzeigen` (zu lang, Tätigkeit)
|
||||
Richtig: `Projekt` · `Feature` · `Vorschlag` · `Planung`
|
||||
Falsch: `Karten prüfen` (Tätigkeit, das ist ein Funktionstitel)
|
||||
Falsch: `Verwaltung und Anzeige` (zwei Gegenstände)
|
||||
Falsch: `Gespräch` für eine Karte über Anweisungen (führt in die Irre)
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
|
||||
Feld `ziel`, wenn `funktion` leer ist.
|
||||
|
||||
- Beschreibt den Zweck der Karte, nicht die Bedienung
|
||||
- Entfällt, wenn der Titel selbsterklärend ist — dann bleibt das Feld leer
|
||||
- Ergänzt den Titel, bis er eindeutig ist
|
||||
- Lässt erwarten, welche Funktionen auf der Karte stehen
|
||||
- Beginnt mit einem Verb
|
||||
- Erklärt den Titel nicht mit sich selbst
|
||||
- Beschreibt den Zweck, nie die Bedienung
|
||||
|
||||
Richtig: `Gruppiert Informationen zu ähnlichen Funktionen`
|
||||
Falsch: `Klick auf die Karte öffnet den Vollmodus` (Bedienung gehört zu Testen)
|
||||
Richtig: `Bündelt die Features einer Anwendung samt Verzeichnis`
|
||||
Falsch: `Gruppiert Features für ein Projekt` auf der Karte `Projekt` (zirkulär)
|
||||
Falsch: `Eine Änderung, die auf Zustimmung wartet` (Definition ohne Verb)
|
||||
Falsch: `LMB auf die Karte öffnet sie` (Bedienung gehört zu Testen)
|
||||
|
||||
@@ -4,10 +4,13 @@ Feld `regeln`, wenn `funktion` gesetzt ist. Gilt nur für diese Funktion.
|
||||
|
||||
- Eine Zeile je Regel
|
||||
- Genau eine Aussage je Zeile; zwei Aussagen werden zu zwei Regeln
|
||||
- Sichert etwas zu, das man sonst nicht sieht
|
||||
- Beschreibt eine Eigenschaft oder Bedingung, keinen Ablaufschritt
|
||||
- Steht nicht schon in den Testschritten
|
||||
- Steht nicht schon als Regel der Karte
|
||||
- Keine Aufzählung mit Komma oder „und" zweier gleichrangiger Aussagen
|
||||
- Ein Icon-Name allein ist eine gültige Regel
|
||||
|
||||
Richtig: `x-Icon` · `Kern blau umrandet` · `Aktualisiert den Dateinamen`
|
||||
Falsch: `Kern blau umrandet, Optional grün umrandet` (zwei Aussagen)
|
||||
Falsch: `Klick auf Badge` (Ablaufschritt, gehört zu Testen)
|
||||
Richtig: `Titel ist Pflicht` · `Rückfrage vor dem Entfernen`
|
||||
Falsch: `Titel eingeben, dann bestätigen` (zwei Aussagen)
|
||||
Falsch: `LMB auf Badge` (Ablaufschritt, gehört zu Testen)
|
||||
Falsch: `Entsteht leer`, wenn die Testschritte keine Eingabe zeigen (schon sichtbar)
|
||||
|
||||
@@ -2,22 +2,40 @@
|
||||
|
||||
Feld `testen`. Gibt es nur bei Funktionen, nie auf Kartenebene.
|
||||
|
||||
Pflicht bei jeder Funktion. Eine Funktion ist etwas, das man für sich testen kann —
|
||||
ohne Ablauf ist sie nur eine Behauptung. Ziel und Regeln dürfen fehlen, Testen nie.
|
||||
Weiß man den Ablauf nicht, ist es keine Funktion, sondern eine offene Frage.
|
||||
|
||||
- Eine Zeile je Schritt
|
||||
- Genau ein Ablauf: handeln, handeln, Ergebnis
|
||||
- Nach dem Ergebnis folgt keine Handlung mehr
|
||||
- Schritte in Reihenfolge der Bedienung
|
||||
- Beginnt mit der Vorbedingung, wenn eine nötig ist
|
||||
- Kein Schritt der Bedienung fehlt
|
||||
- Jeder Schritt ist ohne Vorwissen ausführbar
|
||||
- Letzte Zeile beschreibt den Endzustand, keine Handlung
|
||||
- Handlungen als Nominalstil mit Maustaste oder Verb im Infinitiv
|
||||
- Handlungen als Nominalstil mit Maustaste, Kommando oder Verb im Infinitiv
|
||||
- Ein Kommando steht wörtlich im Zitat und ist so aufrufbar
|
||||
|
||||
Richtig:
|
||||
```
|
||||
- Vollmodus öffnen
|
||||
- RMB auf Funktion
|
||||
- Feature öffnen
|
||||
- RMB auf die Funktion
|
||||
- Klick auf "Funktion entfernen"
|
||||
- Bestätigen
|
||||
- Funktion entfernt
|
||||
```
|
||||
Falsch: letzte Zeile `Klick zum entfernen` (Handlung statt Endzustand)
|
||||
|
||||
Auf der Kommandozeile gilt dasselbe — der Aufruf ist die Handlung:
|
||||
```
|
||||
- Befehl "make install" ausführen
|
||||
- Abmelden und wieder anmelden
|
||||
- Anwendung läuft automatisch
|
||||
```
|
||||
Falsch: `Installationsskript starten` (sagt nicht, wie)
|
||||
Falsch: `Der Prüfschritt kopiert die Desktop-Datei` (Bauweise statt Bedienung)
|
||||
Falsch: letzte Zeile `Klick zum Entfernen` (Handlung statt Endzustand)
|
||||
Falsch: `Funktion entfernen wählen` (sagt nicht, wo)
|
||||
|
||||
Falsch, weil zwei Abläufe in einer Funktion stehen:
|
||||
```
|
||||
|
||||
@@ -3,9 +3,18 @@
|
||||
Feld `titel`, wenn `funktion` gesetzt ist.
|
||||
|
||||
- Kurzsatz aus Objekt und Verb im Infinitiv
|
||||
- Beschreibt etwas, das man für sich testen kann
|
||||
- Nennt den Gegenstand der Karte, wenn das nicht lügt
|
||||
- Genau eine Tätigkeit
|
||||
- Endet auf ein Verb im Infinitiv
|
||||
- Nennt eine Handlung, keinen Bereich, keinen Zustand
|
||||
- Die Handlung löst ein Mensch aus, nicht das System
|
||||
- Nennt die Wirkung, nie den Auslöser — der steht in den Testschritten
|
||||
|
||||
Richtig: `Feature erstellen` · `Anzeigemodus umschalten` · `Feature als Datei speichern`
|
||||
Falsch: `Erstellung von Features` (Substantivierung) · `Feature erstellen und öffnen` (zwei Tätigkeiten) · `Galerie im Modal` (ein Bereich) · `Preis aktualisiert` (ein Zustand) · `In den Warenkorb` (kein Verb)
|
||||
Richtig: `Feature anlegen` · `Vorschlag annehmen` · `Sicht wechseln`
|
||||
Richtig: `Anwendung installieren` · `Autostart aktivieren` · `Tests ausführen`
|
||||
Falsch: `Erstellung von Features` (Substantivierung)
|
||||
Falsch: `Feature anlegen und öffnen` (zwei Tätigkeiten)
|
||||
Falsch: `Galerie im Modal` (ein Bereich) · `Preis aktualisiert` (ein Zustand)
|
||||
Falsch: `Änderung markieren` (das System markiert, gehört in die Regeln)
|
||||
Falsch: `Befehl "make install" ausführen` (der Auslöser, gehört zu Testen)
|
||||
Falsch: `LMB auf Speichern` (der Auslöser, gehört zu Testen)
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
Feld `ziel`, wenn `funktion` gesetzt ist.
|
||||
|
||||
- Beschreibt den Zweck der Funktion, nicht die Bedienung
|
||||
- Entfällt, wenn der Funktionstitel selbsterklärend ist — dann bleibt das Feld leer
|
||||
- Ergänzt den Titel um das Warum
|
||||
- Beginnt mit einem Verb
|
||||
- Entfällt, wenn der Titel selbsterklärend ist — dann bleibt das Feld leer
|
||||
- Wiederholt den Titel nicht
|
||||
- Beschreibt den Zweck, nie die Bedienung
|
||||
|
||||
Richtig: `Beschreibt kurz das Kernziel der Funktion`
|
||||
Falsch: `Klick auf Regeln der Funktion` (Bedienung gehört zu Testen)
|
||||
Richtig: `Trennt tragende von verzichtbaren Features`
|
||||
Falsch: `Legt die Vision an` auf `Vision anlegen` (wiederholt den Titel)
|
||||
Falsch: `LMB auf Regeln der Funktion` (Bedienung gehört zu Testen)
|
||||
|
||||
@@ -37,10 +37,17 @@ _INFINITIV = re.compile(r"(?:e[lr]?n|ln|rn)$", re.I)
|
||||
# Eine Handlung steht als Infinitiv am Anfang oder am Ende der Zeile („Bestätigen im
|
||||
# Modal", „Text ändern") oder beginnt mit einer Taste. Alles andere ist ein Ergebnis.
|
||||
# Nur Anfang und Ende, nicht irgendwo: deutsche Mehrzahl endet auch auf -en.
|
||||
_TASTE = re.compile(r"^(?:LMB|RMB|MMB|Klick|Doppelklick|Enter|Escape|Strg|Tab)\b", re.I)
|
||||
# „Befehl" und „Kommando" stehen dabei wie eine Taste: auf der Kommandozeile ist der
|
||||
# Aufruf die Handlung, und ohne sie wäre ein Setup nicht bedienbar zu beschreiben.
|
||||
_TASTE = re.compile(
|
||||
r"^(?:LMB|RMB|MMB|Klick|Doppelklick|Enter|Escape|Strg|Tab|Befehl|Kommando)\b", re.I)
|
||||
|
||||
SATZENDE = ".;"
|
||||
_KLAMMER = re.compile(r"[()/]")
|
||||
# Ein Zitat ist eine Einheit: ein Menüeintrag oder ein Kommando. „Befehl "make install"
|
||||
# ausführen" sind drei Wörter, nicht vier, und der Schrägstrich in „npm run build/dev"
|
||||
# ist keiner von uns. Darum wird außerhalb der Zitate gemessen.
|
||||
_ZITAT = re.compile(r'"[^"]*"|„[^“]*“')
|
||||
# Eine Vorlage ist kein Inhalt. Das Modell schlug `<testschritt>` als Testschritt
|
||||
# vor — formal richtig, gemeint war „hier fehlt noch etwas".
|
||||
_LUECKE = re.compile(r"<[^<>]*>|\.\.\.|\bTODO\b|\bXXX\b", re.I)
|
||||
@@ -58,9 +65,30 @@ def _problem(feld: str, original: str, problem: str, vorschlag: str = "") -> dic
|
||||
return {"feld": feld, "original": original, "problem": problem, "vorschlag": vorschlag}
|
||||
|
||||
|
||||
def _messbar(zeile: str) -> str:
|
||||
"""Die Zeile mit jedem Zitat als einem Wort — so wird gezählt und gesucht."""
|
||||
return _ZITAT.sub("Zitat", zeile)
|
||||
|
||||
|
||||
def _ausserhalb(zeile: str, wandel) -> str:
|
||||
"""Wendet `wandel` nur auf die Teile außerhalb der Zitate an.
|
||||
|
||||
Ein Füllwort im Menüeintrag ist keins — dort steht der Text, den die Anwendung
|
||||
zeigt. Würde er mitgestrichen, verwiese der Testschritt auf einen Knopf, den es
|
||||
nicht gibt.
|
||||
"""
|
||||
teile, letzt = [], 0
|
||||
for m in _ZITAT.finditer(zeile):
|
||||
teile.append(wandel(zeile[letzt:m.start()]))
|
||||
teile.append(m.group(0))
|
||||
letzt = m.end()
|
||||
teile.append(wandel(zeile[letzt:]))
|
||||
return "".join(teile)
|
||||
|
||||
|
||||
def _ohne_wort(zeile: str, wort: str) -> str:
|
||||
neu = re.sub(rf"\s*\b{re.escape(wort)}\b\.?", "", zeile, flags=re.I).strip()
|
||||
return re.sub(r"\s{2,}", " ", neu)
|
||||
weg = lambda t: re.sub(rf"\s*\b{re.escape(wort)}\b\.?", "", t, flags=re.I)
|
||||
return re.sub(r"\s{2,}", " ", _ausserhalb(zeile, weg)).strip()
|
||||
|
||||
|
||||
def _reparierbar(zeile: str) -> tuple[list[str], str]:
|
||||
@@ -70,7 +98,7 @@ def _reparierbar(zeile: str) -> tuple[list[str], str]:
|
||||
gruende.append("Satzzeichen am Zeilenende")
|
||||
neu = neu[:-1].rstrip()
|
||||
for wort in FUELLWOERTER:
|
||||
if re.search(rf"\b{wort}\b", neu, re.I):
|
||||
if re.search(rf"\b{wort}\b", _messbar(neu), re.I):
|
||||
gruende.append(f"Füllwort „{wort}“")
|
||||
neu = _ohne_wort(neu, wort)
|
||||
return gruende, neu
|
||||
@@ -79,19 +107,24 @@ def _reparierbar(zeile: str) -> tuple[list[str], str]:
|
||||
def _umschreiben(bereich: str, feld: str, zeile: str) -> list[str]:
|
||||
"""Verstöße, die der Code sieht, aber nicht beheben kann."""
|
||||
gruende = []
|
||||
if _KLAMMER.search(zeile):
|
||||
gemessen = _messbar(zeile)
|
||||
if _KLAMMER.search(gemessen):
|
||||
gruende.append("Klammer oder Schrägstrich")
|
||||
if _LUECKE.search(zeile):
|
||||
if _LUECKE.search(gemessen):
|
||||
gruende.append("Platzhalter statt Inhalt")
|
||||
grenze = WORTGRENZEN.get((bereich, feld))
|
||||
if grenze and len(zeile.split()) > grenze:
|
||||
if grenze and len(gemessen.split()) > grenze:
|
||||
gruende.append(f"Mehr als {grenze} Wörter")
|
||||
if bereich == "funktion" and feld == "titel":
|
||||
woerter = zeile.split()
|
||||
woerter = gemessen.split()
|
||||
if woerter and not _INFINITIV.search(woerter[-1]):
|
||||
gruende.append("Kein Verb im Infinitiv am Ende")
|
||||
# Der Titel nennt die Wirkung, nicht den Griff. „Befehl "make install"
|
||||
# ausführen" ist ein Testschritt — als Titel sagt er nicht, was danach gilt.
|
||||
if _TASTE.match(zeile):
|
||||
gruende.append("Auslöser statt Wirkung im Titel")
|
||||
if feld == "ziel":
|
||||
saetze = [s.strip() for s in re.split(r"[.!?]+", zeile) if s.strip()]
|
||||
saetze = [s.strip() for s in re.split(r"[.!?]+", gemessen) if s.strip()]
|
||||
if len(saetze) > ZIEL_SAETZE:
|
||||
gruende.append(f"Mehr als {ZIEL_SAETZE} Sätze")
|
||||
if any(len(s.split()) > ZIEL_WOERTER for s in saetze):
|
||||
@@ -100,7 +133,7 @@ def _umschreiben(bereich: str, feld: str, zeile: str) -> list[str]:
|
||||
|
||||
|
||||
def _handlung(zeile: str) -> bool:
|
||||
woerter = zeile.split()
|
||||
woerter = _messbar(zeile).split()
|
||||
if not woerter:
|
||||
return True
|
||||
return bool(_TASTE.match(zeile) or _INFINITIV.search(woerter[-1])
|
||||
@@ -115,10 +148,12 @@ def _zweiter_ablauf(zeilen: list[str]) -> str:
|
||||
„Bildergalerie bedienen" mit blättern, Miniatur wählen und Großansicht in einem.
|
||||
"""
|
||||
ergebnis = False
|
||||
for zeile in zeilen:
|
||||
for i, zeile in enumerate(zeilen):
|
||||
if ergebnis and _handlung(zeile):
|
||||
return zeile
|
||||
if not _handlung(zeile):
|
||||
# Die erste Zeile darf ein Zustand sein: das ist die Vorbedingung, nicht das
|
||||
# Ergebnis. „Badge ist sichtbar" vor „RMB auf Badge" ist ein Ablauf, nicht zwei.
|
||||
if i and not _handlung(zeile):
|
||||
ergebnis = True
|
||||
return ""
|
||||
|
||||
@@ -137,14 +172,15 @@ def _zeile(bereich: str, feld: str, zeile: str) -> list[dict]:
|
||||
def befunde(bereich: str, felder: dict) -> list[dict]:
|
||||
"""Alle messbaren Verstöße einer Prüfstelle, in Reihenfolge der Felder."""
|
||||
raus = []
|
||||
# Ein bloßer Titel beschreibt nichts — und lässt sich über alles stülpen. Der
|
||||
# Prüfer hielt damit einen Druckknopf für „Modal mit Tastatur steuern".
|
||||
# Testschritte sind Pflicht. Eine Funktion ist definiert als etwas, das man für
|
||||
# sich testen kann — ohne Ablauf ist die Behauptung unbelegt und der Titel lässt
|
||||
# sich über alles stülpen. Ziel und Regeln bleiben freiwillig.
|
||||
# Nur wenn die ganze Funktion vorliegt: bei einem einzelnen Feld sagt das Fehlen
|
||||
# der anderen nichts.
|
||||
inhaltsfelder = ("ziel", "regeln", "testen")
|
||||
if bereich == "funktion" and all(f in felder for f in inhaltsfelder) \
|
||||
and not any((felder.get(f) or "").strip() for f in inhaltsfelder):
|
||||
raus.append(_problem("testen", "", "Funktion ohne Ziel, Regeln und Testen"))
|
||||
and not (felder.get("testen") or "").strip():
|
||||
raus.append(_problem("testen", "", "Funktion ohne Testschritte"))
|
||||
return raus
|
||||
for feld, text in felder.items():
|
||||
if feld == "badge":
|
||||
|
||||
418
backend/tests/test_auftrag.py
Normal file
@@ -0,0 +1,418 @@
|
||||
"""Agenten-Übergabe: der Auftrag beschreibt den Diff, der Start braucht ein Verzeichnis."""
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
import auftrag
|
||||
import features
|
||||
import planung
|
||||
import projekte
|
||||
import verzeichnis
|
||||
|
||||
T = "-" * 40
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def projekt(datenordner):
|
||||
projekte.anlegen("A")
|
||||
features.anlegen("A", f"<!-- titel -->\nGalerie\n{T}\n<!-- funktion -->\nBild wählen\n")
|
||||
features.anlegen("A", f"<!-- titel -->\nShop\n{T}\n<!-- funktion -->\nKarte kaufen\n")
|
||||
yield "A"
|
||||
auftrag._laeufe.clear()
|
||||
|
||||
|
||||
def test_ohne_planung_kein_auftrag(projekt):
|
||||
assert auftrag.bau_auftrag(projekt) == ("", [])
|
||||
|
||||
|
||||
def test_leere_planung_kein_auftrag(projekt):
|
||||
planung.starte(projekt)
|
||||
assert auftrag.bau_auftrag(projekt) == ("", [])
|
||||
|
||||
|
||||
def test_auftrag_nennt_diff_und_sollzustand(projekt):
|
||||
planung.starte(projekt)
|
||||
features.anlegen(projekt, f"<!-- titel -->\nMerkliste\n{T}\n<!-- funktion -->\nProdukt merken\n")
|
||||
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop")
|
||||
features.loeschen(projekt, f["id"])
|
||||
|
||||
text, schritte = auftrag.bau_auftrag(projekt)
|
||||
texte = [s["text"] for s in schritte]
|
||||
assert "Merkliste / Produkt merken: PRÜFEN" in texte
|
||||
assert "Karte „Shop“ streichen" in texte
|
||||
assert all(s in text for s in texte)
|
||||
# Die Zuordnung steht daneben, nicht nur im Satz
|
||||
assert {"text": "Merkliste / Produkt merken: PRÜFEN", "karte": "Merkliste",
|
||||
"funktion": "Produkt merken"} in schritte
|
||||
assert {"text": "Karte „Shop“ streichen", "karte": "Shop",
|
||||
"funktion": ""} in schritte
|
||||
# Sollzustand: die neue Karte steht voll drin, die gestrichene nicht
|
||||
assert "<!-- funktion -->\nProdukt merken" in text
|
||||
assert "Karte kaufen" not in text.split("Die betroffenen Karten")[1]
|
||||
|
||||
|
||||
def test_start_braucht_verzeichnis(projekt):
|
||||
assert auftrag.starte(projekt, "tu was", ["x"]) is False
|
||||
|
||||
|
||||
def test_start_braucht_auftrag(projekt, tmp_path):
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
assert auftrag.starte(projekt, "", []) is False
|
||||
|
||||
|
||||
class Strom:
|
||||
"""Attrappe des Claude-Prozesses: gibt vorbereitete Stream-Zeilen aus."""
|
||||
|
||||
def __init__(self, zeilen, rc=0, gesehen=None):
|
||||
import json as _json
|
||||
self._zeilen = [(_json.dumps(z) + "\n").encode() for z in zeilen]
|
||||
self.returncode = rc
|
||||
self._gesehen = gesehen if gesehen is not None else {}
|
||||
|
||||
class Stdin:
|
||||
def write(s, daten): self._gesehen["eingabe"] = daten.decode()
|
||||
async def drain(s): pass
|
||||
def close(s): pass
|
||||
self.stdin = Stdin()
|
||||
|
||||
class Stdout:
|
||||
async def readline(s):
|
||||
return self._zeilen.pop(0) if self._zeilen else b""
|
||||
self.stdout = Stdout()
|
||||
|
||||
class Stderr:
|
||||
async def read(s): return b""
|
||||
self.stderr = Stderr()
|
||||
|
||||
async def wait(self):
|
||||
return self.returncode
|
||||
|
||||
|
||||
def text_ereignis(text):
|
||||
return {"type": "assistant", "message": {"content": [{"type": "text", "text": text}]}}
|
||||
|
||||
|
||||
def test_start_fuehrt_claude_im_verzeichnis_aus(projekt, tmp_path, monkeypatch):
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
planung.starte(projekt)
|
||||
gesehen = {}
|
||||
|
||||
async def unecht(*kommando, cwd, **k):
|
||||
gesehen["kommando"] = kommando
|
||||
gesehen["cwd"] = cwd
|
||||
return Strom([{"type": "result", "result": "fertig"}], gesehen=gesehen)
|
||||
|
||||
monkeypatch.setattr(asyncio, "create_subprocess_exec", unecht)
|
||||
|
||||
async def lauf():
|
||||
assert auftrag.starte(projekt, "Setze um: X",
|
||||
[{"text": "S1", "karte": "", "funktion": ""}]) is True
|
||||
assert auftrag.status(projekt)["laeuft"] is True
|
||||
await asyncio.gather(*auftrag._aufgaben)
|
||||
|
||||
asyncio.run(lauf())
|
||||
assert gesehen["kommando"][0] == "claude"
|
||||
assert "--output-format" in gesehen["kommando"]
|
||||
assert gesehen["cwd"] == str(tmp_path)
|
||||
assert gesehen["eingabe"] == "Setze um: X"
|
||||
stand = auftrag.status(projekt)
|
||||
assert stand["text"] == "fertig"
|
||||
assert stand["laeuft"] is False
|
||||
|
||||
|
||||
def test_schritte_werden_abgehakt_und_planung_uebernommen(projekt, tmp_path, monkeypatch):
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
planung.starte(projekt)
|
||||
features.anlegen(projekt, f"<!-- titel -->\nMerkliste\n{T}\n<!-- funktion -->\nProdukt merken\n")
|
||||
anweisung, schritte = auftrag.bau_auftrag(projekt)
|
||||
|
||||
async def unecht(*a, **k):
|
||||
return Strom([
|
||||
{"type": "assistant", "message": {"content": [
|
||||
{"type": "tool_use", "name": "Edit", "input": {"file_path": "x.py"}}]}},
|
||||
text_ereignis(f'ERLEDIGT: {schritte[0]["text"]}'),
|
||||
{"type": "result", "result": "alles gebaut"},
|
||||
])
|
||||
|
||||
monkeypatch.setattr(asyncio, "create_subprocess_exec", unecht)
|
||||
|
||||
async def lauf():
|
||||
auftrag.starte(projekt, anweisung, schritte)
|
||||
await asyncio.gather(*auftrag._aufgaben)
|
||||
|
||||
asyncio.run(lauf())
|
||||
stand = auftrag.status(projekt)
|
||||
assert stand["schritte"] == [{**schritte[0], "fertig": True}]
|
||||
assert stand["uebernommen"] is True
|
||||
assert planung.laeuft(projekt) is False
|
||||
assert "Merkliste" in [f["sektionen"]["titel"] for f in features.liste(projekt)]
|
||||
|
||||
|
||||
def test_fehlschlag_laesst_die_planung_stehen(projekt, tmp_path, monkeypatch):
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
planung.starte(projekt)
|
||||
features.anlegen(projekt, f"<!-- titel -->\nMerkliste\n{T}\n<!-- funktion -->\nProdukt merken\n")
|
||||
anweisung, schritte = auftrag.bau_auftrag(projekt)
|
||||
|
||||
async def unecht(*a, **k):
|
||||
return Strom([], rc=1)
|
||||
|
||||
monkeypatch.setattr(asyncio, "create_subprocess_exec", unecht)
|
||||
|
||||
async def lauf():
|
||||
auftrag.starte(projekt, anweisung, schritte)
|
||||
await asyncio.gather(*auftrag._aufgaben)
|
||||
|
||||
asyncio.run(lauf())
|
||||
stand = auftrag.status(projekt)
|
||||
assert stand["uebernommen"] is False
|
||||
assert stand["fehler"]
|
||||
assert planung.laeuft(projekt) is True
|
||||
assert "Merkliste" not in [f["sektionen"]["titel"] for f in features.liste(projekt, nur_stand=True)]
|
||||
|
||||
|
||||
def test_ungefaehre_meldung_hakt_den_naechsten_schritt_ab():
|
||||
lauf = {"schritte": [{"text": "Galerie / Bild wählen: NEU", "fertig": False},
|
||||
{"text": "Karte „Shop“ streichen", "fertig": False}]}
|
||||
auftrag._hake_ab("Test", lauf, "ERLEDIGT: Galerie / Bild wählen (NEU)")
|
||||
assert lauf["schritte"][0]["fertig"] is True
|
||||
auftrag._hake_ab("Test", lauf, "ERLEDIGT: völlig anderes Zeug")
|
||||
assert lauf["schritte"][1]["fertig"] is False
|
||||
|
||||
|
||||
def test_fehlender_claude_wird_gemeldet(projekt, tmp_path, monkeypatch):
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
|
||||
async def kaputt(*a, **k):
|
||||
raise FileNotFoundError("claude")
|
||||
|
||||
monkeypatch.setattr(asyncio, "create_subprocess_exec", kaputt)
|
||||
|
||||
async def lauf():
|
||||
auftrag.starte(projekt, "X", [{"text": "S", "karte": "", "funktion": ""}])
|
||||
await asyncio.gather(*auftrag._aufgaben)
|
||||
|
||||
asyncio.run(lauf())
|
||||
assert "claude-CLI nicht gefunden" in auftrag.status(projekt)["fehler"]
|
||||
assert auftrag.status(projekt)["laeuft"] is False
|
||||
|
||||
|
||||
def test_zweiter_start_wird_abgelehnt(projekt, tmp_path):
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
auftrag._laeufe[projekt] = {"laeuft": True, "fehler": "", "text": "",
|
||||
"schritte": [], "aktivitaet": "", "uebernommen": False}
|
||||
with pytest.raises(ValueError):
|
||||
auftrag.starte(projekt, "X", [{"text": "S", "karte": "", "funktion": ""}])
|
||||
|
||||
|
||||
# ------------------------------------------------------------- Verzeichnis
|
||||
|
||||
def test_verzeichnis_wird_gemerkt(projekt, tmp_path):
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
assert verzeichnis.lies(projekt) == str(tmp_path)
|
||||
verzeichnis.loesche(projekt)
|
||||
assert verzeichnis.lies(projekt) == ""
|
||||
|
||||
|
||||
def test_verzeichnis_lehnt_wurzel_und_relatives_ab(projekt):
|
||||
with pytest.raises(ValueError):
|
||||
verzeichnis.pruefe("/")
|
||||
with pytest.raises(ValueError):
|
||||
verzeichnis.pruefe("relativ/pfad")
|
||||
with pytest.raises(FileNotFoundError):
|
||||
verzeichnis.pruefe("/gibt/es/nicht")
|
||||
|
||||
|
||||
def test_verzeichnis_liegt_im_stand_nicht_in_der_kopie(projekt, tmp_path):
|
||||
planung.starte(projekt)
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
planung.brich_ab(projekt)
|
||||
assert verzeichnis.lies(projekt) == str(tmp_path)
|
||||
|
||||
|
||||
# ------------------------------------------------------------- Durchblättern
|
||||
|
||||
def test_ordner_listet_nur_sichtbare_verzeichnisse(tmp_path):
|
||||
(tmp_path / "b").mkdir()
|
||||
(tmp_path / "A").mkdir()
|
||||
(tmp_path / ".versteckt").mkdir()
|
||||
(tmp_path / "datei.txt").write_text("x")
|
||||
antwort = verzeichnis.ordner(str(tmp_path))
|
||||
assert antwort["ordner"] == ["A", "b"]
|
||||
assert antwort["pfad"] == str(tmp_path)
|
||||
assert antwort["eltern"] == str(tmp_path.parent)
|
||||
|
||||
|
||||
def test_ordner_ohne_pfad_beginnt_daheim():
|
||||
from pathlib import Path
|
||||
assert verzeichnis.ordner("")["pfad"] == str(Path.home())
|
||||
|
||||
|
||||
def test_ordner_lehnt_datei_und_relatives_ab(tmp_path):
|
||||
(tmp_path / "d.txt").write_text("x")
|
||||
with pytest.raises(FileNotFoundError):
|
||||
verzeichnis.ordner(str(tmp_path / "d.txt"))
|
||||
with pytest.raises(ValueError):
|
||||
verzeichnis.ordner("relativ")
|
||||
|
||||
|
||||
def test_vision_gehoert_nie_zum_auftrag(projekt):
|
||||
features.anlegen(projekt, "<!-- titel -->\nVision\n<!-- art -->\nvision\n<!-- ziel -->\nAlt\n")
|
||||
planung.starte(projekt)
|
||||
v = next(f for f in features.liste(projekt) if f["sektionen"]["art"] == "vision")
|
||||
features.speichern(projekt, v["id"], v["roh"].replace("Alt", "Neu"))
|
||||
assert auftrag.bau_auftrag(projekt) == ("", [])
|
||||
|
||||
features.anlegen(projekt, f"<!-- titel -->\nMerkliste\n{T}\n<!-- funktion -->\nProdukt merken\n")
|
||||
text, schritte = auftrag.bau_auftrag(projekt)
|
||||
assert [s["text"] for s in schritte] == ["Merkliste / Produkt merken: PRÜFEN"]
|
||||
assert "Vision" not in text
|
||||
|
||||
|
||||
# ------------------------------------------------- Stand: bestellt wird gebaut
|
||||
|
||||
def _stand(projekt, karte, funktion):
|
||||
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == karte)
|
||||
return next(x["stand"] for x in f["sektionen"]["funktionen"] if x["text"] == funktion)
|
||||
|
||||
|
||||
def test_abgehakte_funktion_gilt_als_gebaut(projekt, tmp_path, monkeypatch):
|
||||
"""Der Agent hat es gebaut — dann darf die Karte nicht „bestellt“ behaupten."""
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
planung.starte(projekt)
|
||||
features.anlegen(projekt, f"<!-- titel -->\nMerkliste\n{T}\n<!-- funktion -->\n"
|
||||
f"Produkt merken\n<!-- stand -->\noffen\n{T}\n"
|
||||
f"<!-- funktion -->\nProdukt entfernen\n<!-- stand -->\noffen\n")
|
||||
anweisung, schritte = auftrag.bau_auftrag(projekt)
|
||||
merken = next(s for s in schritte if s["funktion"] == "Produkt merken")
|
||||
|
||||
async def unecht(*a, **k):
|
||||
return Strom([text_ereignis(f'ERLEDIGT: {merken["text"]}'),
|
||||
{"type": "result", "result": "eins gebaut"}])
|
||||
|
||||
monkeypatch.setattr(asyncio, "create_subprocess_exec", unecht)
|
||||
|
||||
async def lauf():
|
||||
auftrag.starte(projekt, anweisung, schritte)
|
||||
await asyncio.gather(*auftrag._aufgaben)
|
||||
|
||||
asyncio.run(lauf())
|
||||
# Nur der abgehakte Schritt wandert um; der andere bleibt bestellt
|
||||
assert _stand(projekt, "Merkliste", "Produkt merken") == "gebaut"
|
||||
assert _stand(projekt, "Merkliste", "Produkt entfernen") == "offen"
|
||||
|
||||
|
||||
def test_gestrichene_funktion_wird_nicht_umgestellt(projekt, tmp_path):
|
||||
"""Was weg ist, ist nicht gebaut — der Schritt trägt darum keinen Namen."""
|
||||
planung.starte(projekt)
|
||||
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie")
|
||||
features.speichern(projekt, f["id"], "<!-- titel -->\nGalerie\n")
|
||||
_, schritte = auftrag.bau_auftrag(projekt)
|
||||
weg = next(s for s in schritte if "Bild wählen" in s["text"])
|
||||
assert weg["funktion"] == ""
|
||||
|
||||
|
||||
def test_offen_vermerk_bleibt_bei_anderer_funktion(projekt):
|
||||
roh = ("<!-- titel -->\nGalerie\n"
|
||||
"<!-- funktion -->\nBild wählen\n<!-- stand -->\noffen\n"
|
||||
"<!-- funktion -->\nBild schließen\n<!-- stand -->\noffen\n")
|
||||
neu = auftrag._als_gebaut(roh, "Bild schließen")
|
||||
assert neu.count("offen") == 1
|
||||
assert "Bild wählen\n<!-- stand -->\noffen" in neu
|
||||
|
||||
|
||||
def test_unbekannte_bloecke_bleiben_erhalten(projekt):
|
||||
"""Textoperation statt Neuschreiben: der Rest der Datei bleibt Zeichen für Zeichen."""
|
||||
roh = ("<!-- titel -->\nGalerie\n<!-- eigenes -->\nnicht anfassen\n"
|
||||
"<!-- funktion -->\nBild wählen\n<!-- stand -->\noffen\n"
|
||||
"<!-- regeln -->\n- Eine Regel\n")
|
||||
neu = auftrag._als_gebaut(roh, "Bild wählen")
|
||||
assert "<!-- eigenes -->\nnicht anfassen" in neu
|
||||
assert "<!-- regeln -->\n- Eine Regel" in neu
|
||||
assert "offen" not in neu
|
||||
|
||||
|
||||
# ---------------------------------------- offen heißt: noch nicht bewiesen
|
||||
|
||||
def _auf_offen(projekt, karte, funktion):
|
||||
"""Wie ein Klick auf den Stand: gebaut zurück auf offen."""
|
||||
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == karte)
|
||||
roh = f["roh"].replace(f"<!-- funktion -->\n{funktion}\n",
|
||||
f"<!-- funktion -->\n{funktion}\n<!-- stand -->\noffen\n")
|
||||
features.speichern(projekt, f["id"], roh)
|
||||
|
||||
|
||||
def test_zurueckgesetzte_funktion_kommt_in_die_arbeitsliste(projekt):
|
||||
"""Eine kaputte Umsetzung meldet man, indem man die Funktion auf offen setzt.
|
||||
|
||||
Die Karte ändert sich dadurch, aber sonst nichts — vorher blieb der Klick folgenlos.
|
||||
"""
|
||||
planung.starte(projekt)
|
||||
_auf_offen(projekt, "Galerie", "Bild wählen")
|
||||
text, schritte = auftrag.bau_auftrag(projekt)
|
||||
assert [s["text"] for s in schritte] == ["Galerie / Bild wählen: PRÜFEN"]
|
||||
# Der Sollzustand der Karte gehört dazu, sonst weiß der Agent nicht, wogegen er prüft
|
||||
assert "<!-- funktion -->\nBild wählen" in text
|
||||
assert auftrag.PRUEFEN in text
|
||||
|
||||
|
||||
def test_offene_funktion_ohne_kartenaenderung(projekt, tmp_path):
|
||||
"""Offen in der Kopie und im Stand: kein Diff, trotzdem Arbeit."""
|
||||
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop")
|
||||
features.speichern(projekt, f["id"], f["roh"].replace(
|
||||
"<!-- funktion -->\nKarte kaufen\n",
|
||||
"<!-- funktion -->\nKarte kaufen\n<!-- stand -->\noffen\n"))
|
||||
planung.starte(projekt)
|
||||
assert planung.aenderungen(projekt) == {}
|
||||
_, schritte = auftrag.bau_auftrag(projekt)
|
||||
assert [s["text"] for s in schritte] == ["Shop / Karte kaufen: PRÜFEN"]
|
||||
|
||||
|
||||
def test_offen_schlaegt_geaendert(projekt):
|
||||
"""Eine offene Funktion wird geprüft, nicht bloß angepasst."""
|
||||
planung.starte(projekt)
|
||||
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie")
|
||||
features.speichern(projekt, f["id"], f["roh"].replace(
|
||||
"<!-- funktion -->\nBild wählen\n",
|
||||
"<!-- funktion -->\nBild wählen\n<!-- stand -->\noffen\n"
|
||||
"<!-- regeln -->\n- Eine neue Regel\n"))
|
||||
_, schritte = auftrag.bau_auftrag(projekt)
|
||||
assert [s["text"] for s in schritte] == ["Galerie / Bild wählen: PRÜFEN"]
|
||||
|
||||
|
||||
def test_gebaut_und_geaendert_bleibt_geaendert(projekt):
|
||||
planung.starte(projekt)
|
||||
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie")
|
||||
features.speichern(projekt, f["id"], f["roh"].replace(
|
||||
"<!-- funktion -->\nBild wählen\n",
|
||||
"<!-- funktion -->\nBild wählen\n<!-- regeln -->\n- Eine neue Regel\n"))
|
||||
_, schritte = auftrag.bau_auftrag(projekt)
|
||||
assert [s["text"] for s in schritte] == ["Galerie / Bild wählen: GEÄNDERT"]
|
||||
|
||||
|
||||
def test_gestrichene_karte_zieht_ihre_offenen_nicht_nach(projekt):
|
||||
"""Eine gestrichene Karte darf nicht zusätzlich als „prüfen“ auftauchen."""
|
||||
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop")
|
||||
features.speichern(projekt, f["id"], f["roh"].replace(
|
||||
"<!-- funktion -->\nKarte kaufen\n",
|
||||
"<!-- funktion -->\nKarte kaufen\n<!-- stand -->\noffen\n"))
|
||||
planung.starte(projekt)
|
||||
g = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop")
|
||||
features.loeschen(projekt, g["id"])
|
||||
_, schritte = auftrag.bau_auftrag(projekt)
|
||||
assert [s["text"] for s in schritte] == ["Karte „Shop“ streichen"]
|
||||
|
||||
|
||||
def test_ohne_planung_kein_lauf(projekt):
|
||||
"""Der Agent arbeitet auf der Planung; ohne sie gibt es keinen Auftrag."""
|
||||
_auf_offen(projekt, "Galerie", "Bild wählen")
|
||||
assert auftrag.bau_auftrag(projekt) == ("", [])
|
||||
|
||||
|
||||
def test_auftrag_verlangt_offenlegung_des_ungeprueften(projekt):
|
||||
planung.starte(projekt)
|
||||
_auf_offen(projekt, "Galerie", "Bild wählen")
|
||||
text, _ = auftrag.bau_auftrag(projekt)
|
||||
assert "nicht prüfen konntest" in text
|
||||
assert "Hake nur ab, was du geprüft hast" in text
|
||||
111
backend/tests/test_chat.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""Was das Planungsgespräch darf — und was es nicht sieht.
|
||||
|
||||
Geprüft wird nicht die Antwort des Modells, sondern womit es losgeschickt wird:
|
||||
Werkzeugsatz, Arbeitsverzeichnis und der Absatz im Systemprompt gehören zusammen.
|
||||
Fällt eines auseinander, behauptet das Modell nachgesehen zu haben, ohne zu können.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
import agents
|
||||
import chat
|
||||
import projekte
|
||||
import verzeichnis
|
||||
|
||||
KARTE = ("<!-- titel -->\nUpload\n<!-- art -->\nkern\n"
|
||||
"<!-- ziel -->\nDateien landen im Speicher.\n"
|
||||
"<!-- funktion -->\nDatei wählen\n<!-- testen -->\n- Dialog öffnen\n")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def projekt(datenordner):
|
||||
projekte.anlegen("P")
|
||||
(datenordner / "P" / "upload.md").write_text(KARTE)
|
||||
return "P"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mitschrift(monkeypatch):
|
||||
"""Fängt den Aufruf ab und gibt eine gültige Antwort zurück."""
|
||||
gesehen = {}
|
||||
|
||||
async def antworte(system, inhalt, kommando=None, ordner=None):
|
||||
gesehen.update(system=system, inhalt=inhalt, kommando=kommando, ordner=ordner)
|
||||
return json.dumps({"antwort": "Verstanden.", "karten": []})
|
||||
|
||||
monkeypatch.setattr(agents, "frage_lokal", antworte)
|
||||
return gesehen
|
||||
|
||||
|
||||
async def test_ohne_verzeichnis_kein_lesen(projekt, mitschrift):
|
||||
await chat.frage(projekt, "Was kann das Projekt?")
|
||||
assert mitschrift["kommando"] == agents.PLANUNG_OHNE_CODE
|
||||
assert mitschrift["ordner"] is None
|
||||
assert chat.CODE_OHNE in mitschrift["system"]
|
||||
|
||||
|
||||
async def test_mit_verzeichnis_darf_lesen(projekt, mitschrift, tmp_path):
|
||||
code = tmp_path / "quelltext"
|
||||
code.mkdir()
|
||||
verzeichnis.setze(projekt, str(code))
|
||||
await chat.frage(projekt, "Gibt es den Upload schon?")
|
||||
assert mitschrift["kommando"] == agents.PLANUNG_KOMMANDO
|
||||
assert mitschrift["ordner"] == str(code.resolve())
|
||||
assert chat.CODE_MIT in mitschrift["system"]
|
||||
|
||||
|
||||
async def test_toter_pfad_zaehlt_wie_keiner(projekt, mitschrift, tmp_path):
|
||||
"""Sonst startet der Prozess nicht, und die Meldung zeigt auf die CLI."""
|
||||
code = tmp_path / "weg"
|
||||
code.mkdir()
|
||||
verzeichnis.setze(projekt, str(code))
|
||||
code.rmdir()
|
||||
await chat.frage(projekt, "Und jetzt?")
|
||||
assert mitschrift["kommando"] == agents.PLANUNG_OHNE_CODE
|
||||
assert mitschrift["ordner"] is None
|
||||
|
||||
|
||||
async def test_planung_sucht_nicht_im_web(projekt, mitschrift, tmp_path):
|
||||
"""Fremdes Wissen kommt aus der Recherche, nicht nebenbei in einen Entwurf."""
|
||||
code = tmp_path / "quelltext"
|
||||
code.mkdir()
|
||||
verzeichnis.setze(projekt, str(code))
|
||||
await chat.frage(projekt, "Wie macht man das üblicherweise?")
|
||||
for satz in (agents.PLANUNG_KOMMANDO, agents.PLANUNG_OHNE_CODE):
|
||||
assert "WebSearch" not in _erlaubt(satz)
|
||||
assert "WebFetch" not in _erlaubt(satz)
|
||||
|
||||
|
||||
def test_recherche_sieht_keinen_quelltext():
|
||||
"""Umgekehrt: aus dem Projekt darf nichts in eine Suchanfrage geraten."""
|
||||
erlaubt = _erlaubt(agents.RECHERCHE_KOMMANDO)
|
||||
assert "WebSearch" in erlaubt and "WebFetch" in erlaubt
|
||||
for werkzeug in ("Read", "Glob", "Grep"):
|
||||
assert werkzeug not in erlaubt
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kommando", [
|
||||
agents.PLANUNG_KOMMANDO, agents.PLANUNG_OHNE_CODE, agents.RECHERCHE_KOMMANDO])
|
||||
def test_kein_satz_kann_etwas_anstossen(kommando):
|
||||
"""Fremder Text im Kontext darf nichts auslösen, egal woher er kommt."""
|
||||
gesperrt = _gesperrt(kommando)
|
||||
for werkzeug in ("Write", "Edit", "Bash", "CronCreate", "PushNotification",
|
||||
"SendMessage", "Workflow", "Task"):
|
||||
assert werkzeug in gesperrt
|
||||
assert "--safe-mode" in kommando
|
||||
|
||||
|
||||
def _abschnitt(kommando: tuple, flagge: str) -> list:
|
||||
rest = list(kommando[kommando.index(flagge) + 1:])
|
||||
ende = next((i for i, w in enumerate(rest) if w.startswith("--")), len(rest))
|
||||
return rest[:ende]
|
||||
|
||||
|
||||
def _erlaubt(kommando: tuple) -> list:
|
||||
return _abschnitt(kommando, "--allowed-tools")
|
||||
|
||||
|
||||
def _gesperrt(kommando: tuple) -> list:
|
||||
return _abschnitt(kommando, "--disallowed-tools")
|
||||
@@ -22,13 +22,16 @@ def projekt(datenordner):
|
||||
|
||||
|
||||
def karte(projekt, titel, *funktionen):
|
||||
"""funktionen sind (name, regel) oder (name, regel, [testschritte])."""
|
||||
"""funktionen sind (name, regel) oder (name, regel, [testschritte]).
|
||||
|
||||
Ohne eigene Schritte bekommt die Funktion einen Platzhalter-Ablauf: Testschritte
|
||||
sind Pflicht, und ohne sie bricht die Messung vor allem anderen ab.
|
||||
"""
|
||||
text = f"<!-- titel -->\n{titel}\n"
|
||||
for eintrag in funktionen:
|
||||
name, regel, schritte = (*eintrag, [])[:3]
|
||||
name, regel, schritte = (*eintrag, ["Karte öffnen", "Karte offen"])[:3]
|
||||
text += f"<!-- funktion -->\n{name}\n<!-- regeln -->\n- {regel}\n"
|
||||
if schritte:
|
||||
text += "<!-- testen -->\n" + "".join(f"- {s}\n" for s in schritte)
|
||||
text += "<!-- testen -->\n" + "".join(f"- {s}\n" for s in schritte)
|
||||
return features.anlegen(projekt, text)
|
||||
|
||||
|
||||
@@ -116,14 +119,14 @@ async def test_stilurteil_wird_gemerkt_und_nicht_neu_gefragt(projekt, monkeypatc
|
||||
|
||||
liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt)
|
||||
for a in liste:
|
||||
assert await arbeite(a, None) == []
|
||||
assert await arbeite(a) == []
|
||||
abschluss()
|
||||
erste = modell.rufe
|
||||
assert erste >= len(pruefung.TEMPERATUREN)
|
||||
|
||||
liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt)
|
||||
for a in liste:
|
||||
assert await arbeite(a, None) == []
|
||||
assert await arbeite(a) == []
|
||||
assert modell.rufe == erste # keine einzige neue Anfrage
|
||||
|
||||
|
||||
@@ -136,7 +139,7 @@ async def test_geaenderter_text_wird_neu_gefragt(projekt, monkeypatch):
|
||||
|
||||
liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt)
|
||||
for a in liste:
|
||||
await arbeite(a, None)
|
||||
await arbeite(a)
|
||||
abschluss()
|
||||
vorher = modell.rufe
|
||||
|
||||
@@ -144,7 +147,7 @@ async def test_geaenderter_text_wird_neu_gefragt(projekt, monkeypatch):
|
||||
datei.write_text(datei.read_text().replace("- Knopf", "- Ganz anderer Text"))
|
||||
liste, arbeite, _ = await pruefung._stil_aufgaben(projekt)
|
||||
for a in liste:
|
||||
await arbeite(a, None)
|
||||
await arbeite(a)
|
||||
assert modell.rufe > vorher
|
||||
|
||||
|
||||
@@ -159,7 +162,7 @@ async def test_gemessener_verstoss_kommt_nie_aus_dem_gedaechtnis(projekt, monkey
|
||||
|
||||
for lauf in range(2):
|
||||
liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt)
|
||||
gefunden = [p for a in liste for p in await arbeite(a, None)]
|
||||
gefunden = [p for a in liste for p in await arbeite(a)]
|
||||
abschluss()
|
||||
assert [p["vorschlag"] for p in gefunden] == ["Passwort prüfen"], lauf
|
||||
assert modell.rufe > len(pruefung.TEMPERATUREN) # zweimal wirklich gefragt
|
||||
|
||||
@@ -199,3 +199,33 @@ def test_gespraech_und_gedaechtnis_wandern_mit(projekt):
|
||||
def test_die_kopie_kopiert_sich_nicht_selbst(projekt):
|
||||
planung.starte(projekt)
|
||||
assert not (projekte.wurzel(projekt) / projekte.PLANUNG).exists()
|
||||
|
||||
|
||||
def test_arbeitsverzeichnis_ueberlebt_das_umsetzen(projekt, tmp_path):
|
||||
"""Erst nach dem Planungsstart festgelegt — dann fehlt es in der Kopie.
|
||||
|
||||
Vorher räumte das Umsetzen es mit dem alten Stand weg, und der nächste Lauf
|
||||
fand kein Verzeichnis mehr.
|
||||
"""
|
||||
import verzeichnis
|
||||
planung.starte(projekt)
|
||||
verzeichnis.setze(projekt, str(tmp_path))
|
||||
assert not (planung._kopie(projekt) / verzeichnis.DATEI).exists()
|
||||
|
||||
planung.setze_um(projekt)
|
||||
assert verzeichnis.lies(projekt) == str(tmp_path)
|
||||
|
||||
|
||||
def test_geplantes_verzeichnis_gewinnt(projekt, tmp_path):
|
||||
"""Steht es in beiden, gilt die Kopie — sie ist der neuere Stand."""
|
||||
import verzeichnis
|
||||
alt = tmp_path / "alt"
|
||||
alt.mkdir()
|
||||
verzeichnis.setze(projekt, str(alt))
|
||||
planung.starte(projekt)
|
||||
neu = tmp_path / "neu"
|
||||
neu.mkdir()
|
||||
(planung._kopie(projekt) / verzeichnis.DATEI).write_text(str(neu))
|
||||
|
||||
planung.setze_um(projekt)
|
||||
assert verzeichnis.lies(projekt) == str(neu)
|
||||
|
||||
193
backend/tests/test_recherche.py
Normal file
@@ -0,0 +1,193 @@
|
||||
import pytest
|
||||
|
||||
import agents
|
||||
import projekte
|
||||
import recherche
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def projekt(datenordner):
|
||||
projekte.anlegen("P")
|
||||
return "P"
|
||||
|
||||
|
||||
def test_leeres_projekt_hat_keine_faeden(projekt):
|
||||
assert recherche.liste(projekt) == []
|
||||
|
||||
|
||||
def test_anlegen_gibt_faden_mit_id(projekt):
|
||||
faden = recherche.anlegen(projekt)
|
||||
assert faden["id"] and faden["verlauf"] == []
|
||||
assert [f["id"] for f in recherche.liste(projekt)] == [faden["id"]]
|
||||
|
||||
|
||||
def test_faeden_haben_eigene_ids(projekt):
|
||||
a, b = recherche.anlegen(projekt), recherche.anlegen(projekt)
|
||||
assert a["id"] != b["id"]
|
||||
assert len(recherche.liste(projekt)) == 2
|
||||
|
||||
|
||||
def test_loeschen_trifft_nur_den_einen(projekt):
|
||||
a, b = recherche.anlegen(projekt), recherche.anlegen(projekt)
|
||||
recherche.loeschen(projekt, a["id"])
|
||||
assert [f["id"] for f in recherche.liste(projekt)] == [b["id"]]
|
||||
|
||||
|
||||
def test_loeschen_ohne_faden_ist_404(projekt):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
recherche.loeschen(projekt, "gibtsnicht")
|
||||
|
||||
|
||||
def test_faeden_liegen_im_projektstand_nicht_in_der_planung(projekt):
|
||||
"""Nachgeschlagenes überlebt einen Planungsabbruch — es gehört zum Projekt."""
|
||||
recherche.anlegen(projekt)
|
||||
(projekte.stand(projekt) / projekte.PLANUNG).mkdir()
|
||||
assert len(recherche.liste(projekt)) == 1
|
||||
assert (projekte.stand(projekt) / recherche.DATEI).is_file()
|
||||
|
||||
|
||||
def _antwort(satz="Laut Quelle X: ja."):
|
||||
"""Eine Modellantwort — Markdown, nicht JSON."""
|
||||
async def antworte(system, inhalt, kommando=None, ordner=None):
|
||||
return satz
|
||||
return antworte
|
||||
|
||||
|
||||
async def test_frage_haengt_beide_zeilen_an(projekt, monkeypatch):
|
||||
faden = recherche.anlegen(projekt)
|
||||
monkeypatch.setattr(agents, "frage_lokal", _antwort(" Laut Quelle X: ja. "))
|
||||
erg = await recherche.frage(projekt, faden["id"], "Wie geht das?")
|
||||
assert [(e["rolle"], e["text"]) for e in erg["verlauf"]] == [
|
||||
("person", "Wie geht das?"), ("ki", "Laut Quelle X: ja.")]
|
||||
|
||||
|
||||
async def test_erste_frage_benennt_den_faden(projekt, monkeypatch):
|
||||
faden = recherche.anlegen(projekt)
|
||||
monkeypatch.setattr(agents, "frage_lokal", _antwort("ok"))
|
||||
erg = await recherche.frage(projekt, faden["id"], "Wie lädt man\nzu S3 hoch?")
|
||||
assert erg["titel"] == "Wie lädt man zu S3 hoch?"
|
||||
# Die zweite Frage lässt den Namen stehen: der Reiter soll nicht wandern
|
||||
erg = await recherche.frage(projekt, faden["id"], "Und die Grenzen?")
|
||||
assert erg["titel"] == "Wie lädt man zu S3 hoch?"
|
||||
|
||||
|
||||
async def test_langer_titel_wird_gekuerzt(projekt, monkeypatch):
|
||||
faden = recherche.anlegen(projekt)
|
||||
monkeypatch.setattr(agents, "frage_lokal", _antwort("ok"))
|
||||
erg = await recherche.frage(projekt, faden["id"], "w" * 80)
|
||||
assert len(erg["titel"]) == recherche.TITELLAENGE + 1
|
||||
assert erg["titel"].endswith("…")
|
||||
|
||||
|
||||
async def test_recherche_bekommt_die_websuche(projekt, monkeypatch):
|
||||
"""Der Werkzeugsatz ist der ganze Unterschied zum Planungsgespräch."""
|
||||
faden = recherche.anlegen(projekt)
|
||||
gesehen = {}
|
||||
|
||||
async def antworte(system, inhalt, kommando=None, ordner=None):
|
||||
gesehen.update(kommando=kommando, inhalt=inhalt)
|
||||
return "ok"
|
||||
|
||||
monkeypatch.setattr(agents, "frage_lokal", antworte)
|
||||
await recherche.frage(projekt, faden["id"], "Was gilt draußen?")
|
||||
assert gesehen["kommando"] == agents.RECHERCHE_KOMMANDO
|
||||
|
||||
|
||||
async def test_die_karten_liegen_im_prompt(projekt, monkeypatch):
|
||||
"""Ohne Bestand ist „was fehlt noch" nicht zu beantworten — dann rät das Modell."""
|
||||
(projekte.stand(projekt) / "gold.md").write_text(
|
||||
"<!-- titel -->\nGold\n<!-- art -->\nkern\n"
|
||||
"<!-- ziel -->\nSpieler verdient Gold pro Runde.\n"
|
||||
"<!-- funktion -->\nZinsen erhalten\n<!-- stand -->\noffen\n"
|
||||
"<!-- testen -->\n- Runde spielen\n")
|
||||
faden = recherche.anlegen(projekt)
|
||||
gesehen = {}
|
||||
|
||||
async def antworte(system, inhalt, kommando=None, ordner=None):
|
||||
gesehen["system"] = system
|
||||
return "ok"
|
||||
|
||||
monkeypatch.setattr(agents, "frage_lokal", antworte)
|
||||
await recherche.frage(projekt, faden["id"], "Was fehlt noch?")
|
||||
assert "Zinsen erhalten" in gesehen["system"]
|
||||
# Der Stand ist der Punkt: er unterscheidet Gebautes von Bestelltem
|
||||
assert '"stand": "offen"' in gesehen["system"]
|
||||
# Testabläufe blähen den Prompt und tragen keine Recherche
|
||||
assert "Runde spielen" not in gesehen["system"]
|
||||
|
||||
|
||||
async def test_vision_kommt_mit(projekt, monkeypatch):
|
||||
(projekte.stand(projekt) / "vision.md").write_text(
|
||||
"<!-- titel -->\nVision\n<!-- art -->\nvision\n"
|
||||
"<!-- ziel -->\nTFT im Browser nachbauen.\n")
|
||||
faden = recherche.anlegen(projekt)
|
||||
gesehen = {}
|
||||
|
||||
async def antworte(system, inhalt, kommando=None, ordner=None):
|
||||
gesehen["system"] = system
|
||||
return "ok"
|
||||
|
||||
monkeypatch.setattr(agents, "frage_lokal", antworte)
|
||||
await recherche.frage(projekt, faden["id"], "Und nun?")
|
||||
assert "TFT im Browser nachbauen." in gesehen["system"]
|
||||
|
||||
|
||||
async def test_markdown_bleibt_wie_es_kam(projekt, monkeypatch):
|
||||
"""Die Antwort wird als Markdown angezeigt — der Server fasst sie nicht an."""
|
||||
roh = "Kurz gesagt.\n\n## Festgelegt\n- **5 Gold** pro Runde\n\n## Quellen\n- [Wiki](http://x)"
|
||||
faden = recherche.anlegen(projekt)
|
||||
monkeypatch.setattr(agents, "frage_lokal", _antwort(f"\n{roh}\n"))
|
||||
erg = await recherche.frage(projekt, faden["id"], "Wie geht Gold?")
|
||||
assert erg["verlauf"][-1]["text"] == roh
|
||||
|
||||
|
||||
async def test_leere_frage_wird_abgelehnt(projekt):
|
||||
faden = recherche.anlegen(projekt)
|
||||
with pytest.raises(ValueError):
|
||||
await recherche.frage(projekt, faden["id"], " ")
|
||||
|
||||
|
||||
async def test_geschlossener_faden_verwirft_die_antwort(projekt, monkeypatch):
|
||||
"""Antworten dauern Minuten. Wer inzwischen schließt, will das Ergebnis nicht."""
|
||||
faden = recherche.anlegen(projekt)
|
||||
|
||||
async def antworte(system, inhalt, kommando=None, ordner=None):
|
||||
recherche.loeschen(projekt, faden["id"])
|
||||
return "zu spät"
|
||||
|
||||
monkeypatch.setattr(agents, "frage_lokal", antworte)
|
||||
with pytest.raises(FileNotFoundError):
|
||||
await recherche.frage(projekt, faden["id"], "Was gilt?")
|
||||
assert recherche.liste(projekt) == []
|
||||
|
||||
|
||||
async def test_paralleler_faden_bleibt_erhalten(projekt, monkeypatch):
|
||||
"""Der zweite Faden entsteht, während der erste noch wartet."""
|
||||
a = recherche.anlegen(projekt)
|
||||
neu = {}
|
||||
|
||||
async def antworte(system, inhalt, kommando=None, ordner=None):
|
||||
neu["b"] = recherche.anlegen(projekt)
|
||||
return "fertig"
|
||||
|
||||
monkeypatch.setattr(agents, "frage_lokal", antworte)
|
||||
await recherche.frage(projekt, a["id"], "Frage")
|
||||
faeden = recherche.liste(projekt)
|
||||
assert [f["id"] for f in faeden] == [a["id"], neu["b"]["id"]]
|
||||
# Was der eine Faden erfährt, bleibt beim einen
|
||||
assert len(faeden[0]["verlauf"]) == 2 and faeden[1]["verlauf"] == []
|
||||
|
||||
|
||||
def test_kaputte_datei_gilt_als_leer(projekt):
|
||||
(projekte.stand(projekt) / recherche.DATEI).write_text("{kein json")
|
||||
assert recherche.liste(projekt) == []
|
||||
|
||||
|
||||
async def test_tiefe_haelt_den_faden_kurz(projekt, monkeypatch):
|
||||
faden = recherche.anlegen(projekt)
|
||||
monkeypatch.setattr(agents, "frage_lokal", _antwort("ok"))
|
||||
for i in range(recherche.TIEFE):
|
||||
await recherche.frage(projekt, faden["id"], f"Frage {i}")
|
||||
verlauf = recherche.liste(projekt)[0]["verlauf"]
|
||||
assert len(verlauf) == recherche.TIEFE
|
||||
assert verlauf[-2]["text"] == f"Frage {recherche.TIEFE - 1}"
|
||||
@@ -72,3 +72,41 @@ async def test_pruefung_ohne_konfiguration(client, monkeypatch):
|
||||
async def test_unbekanntes_projekt(client):
|
||||
assert (await client.get("/api/projekte/Fremd/features")).status_code == 404
|
||||
assert (await client.post("/api/projekte/Fremd/features", json={"roh": ROH})).status_code == 404
|
||||
assert (await client.get("/api/projekte/Fremd/recherche")).status_code == 404
|
||||
|
||||
|
||||
async def test_recherche_faeden(client, monkeypatch):
|
||||
import agents
|
||||
|
||||
await client.post("/api/projekte", json={"name": "Alpha"})
|
||||
assert (await client.get("/api/projekte/Alpha/recherche")).json()["faeden"] == []
|
||||
|
||||
a = (await client.post("/api/projekte/Alpha/recherche")).json()
|
||||
b = (await client.post("/api/projekte/Alpha/recherche")).json()
|
||||
assert a["id"] != b["id"]
|
||||
|
||||
async def antworte(system, inhalt, kommando=None, ordner=None):
|
||||
return "## Festgelegt\n- **5 GB** je Sendung"
|
||||
|
||||
monkeypatch.setattr(agents, "frage_lokal", antworte)
|
||||
res = await client.post(f"/api/projekte/Alpha/recherche/{a['id']}",
|
||||
json={"text": "Was gilt?"})
|
||||
assert res.json()["titel"] == "Was gilt?"
|
||||
assert len(res.json()["verlauf"]) == 2
|
||||
assert res.json()["verlauf"][-1]["text"] == "## Festgelegt\n- **5 GB** je Sendung"
|
||||
|
||||
# Der zweite Faden bleibt leer — Fäden teilen sich nichts
|
||||
faeden = (await client.get("/api/projekte/Alpha/recherche")).json()["faeden"]
|
||||
assert [len(f["verlauf"]) for f in faeden] == [2, 0]
|
||||
|
||||
assert (await client.delete(f"/api/projekte/Alpha/recherche/{b['id']}")).status_code == 200
|
||||
assert len((await client.get("/api/projekte/Alpha/recherche")).json()["faeden"]) == 1
|
||||
assert (await client.delete(f"/api/projekte/Alpha/recherche/{b['id']}")).status_code == 404
|
||||
|
||||
|
||||
async def test_recherche_leere_frage(client):
|
||||
await client.post("/api/projekte", json={"name": "Alpha"})
|
||||
faden = (await client.post("/api/projekte/Alpha/recherche")).json()
|
||||
res = await client.post(f"/api/projekte/Alpha/recherche/{faden['id']}",
|
||||
json={"text": " "})
|
||||
assert res.status_code == 400
|
||||
|
||||
@@ -103,7 +103,8 @@ async def test_messung_ist_auftrag_und_tuersteher(datenordner, monkeypatch):
|
||||
f = features.anlegen(
|
||||
"Test",
|
||||
"<!-- titel -->\nLogin\n<!-- funktion -->\nAnmelden\n"
|
||||
"<!-- regeln -->\n- Auch Passwort prüfen.\n",
|
||||
"<!-- regeln -->\n- Auch Passwort prüfen.\n"
|
||||
"<!-- testen -->\n- Anmelden\n- Angemeldet\n",
|
||||
)
|
||||
gesehen = []
|
||||
# Jede Stimme liefert erst einen halbherzigen Vorschlag: Punkt weg, Füllwort bleibt
|
||||
@@ -141,7 +142,8 @@ async def test_gemessener_verstoss_wird_notfalls_selbst_behoben(datenordner, mon
|
||||
f = features.anlegen(
|
||||
"Test",
|
||||
"<!-- titel -->\nLogin\n<!-- funktion -->\nAnmelden\n"
|
||||
"<!-- regeln -->\n- Auch Passwort prüfen.\n",
|
||||
"<!-- regeln -->\n- Auch Passwort prüfen.\n"
|
||||
"<!-- testen -->\n- Anmelden\n- Angemeldet\n",
|
||||
)
|
||||
|
||||
async def sturr(system, inhalt, temperatur=0.0):
|
||||
@@ -226,18 +228,24 @@ def test_zeilenfehler_haben_vorrang():
|
||||
== ["Satzzeichen am Zeilenende, Füllwort „auch“"]
|
||||
|
||||
|
||||
def test_funktion_ohne_jedes_feld_ist_leer():
|
||||
"""Ein bloßer Titel beschreibt nichts — der Prüfer stülpt ihn über alles."""
|
||||
def test_funktion_ohne_testschritte():
|
||||
"""Ohne Ablauf ist der Titel eine Behauptung — der Prüfer stülpt ihn über alles."""
|
||||
b = struktur.befunde("funktion", {"titel": "Modal steuern", "ziel": "",
|
||||
"regeln": "", "testen": ""})
|
||||
assert _probleme(b) == ["Funktion ohne Ziel, Regeln und Testen"]
|
||||
assert _probleme(b) == ["Funktion ohne Testschritte"]
|
||||
|
||||
|
||||
def test_ein_einziges_feld_genuegt():
|
||||
for feld in ("ziel", "regeln", "testen"):
|
||||
def test_ziel_und_regeln_ersetzen_die_testschritte_nicht():
|
||||
for feld in ("ziel", "regeln"):
|
||||
felder = {"titel": "Modal steuern", "ziel": "", "regeln": "", "testen": ""}
|
||||
felder[feld] = "Etwas tun" if feld == "ziel" else "- Etwas tun"
|
||||
assert struktur.befunde("funktion", felder) == [], feld
|
||||
assert _probleme(struktur.befunde("funktion", felder)) \
|
||||
== ["Funktion ohne Testschritte"], feld
|
||||
|
||||
|
||||
def test_testschritte_genuegen():
|
||||
assert struktur.befunde("funktion", {"titel": "Modal steuern", "ziel": "",
|
||||
"regeln": "", "testen": "- Etwas tun"}) == []
|
||||
|
||||
|
||||
def test_einzelnes_feld_loest_nichts_aus():
|
||||
@@ -259,3 +267,59 @@ def test_platzhalter_ist_kein_inhalt():
|
||||
|
||||
def test_kleiner_als_ist_kein_platzhalter():
|
||||
assert not struktur._umschreiben("funktion", "regeln", "Wert 3 < 5")
|
||||
|
||||
|
||||
def test_kommando_als_testschritt():
|
||||
"""Ein Setup wird über die Kommandozeile bedient — das muss zulässig sein."""
|
||||
assert _pruefe("funktion", "testen", '- Befehl "make install" ausführen') == []
|
||||
assert _pruefe("funktion", "titel", "Anwendung installieren") == []
|
||||
|
||||
|
||||
def test_zitat_zaehlt_als_ein_wort():
|
||||
"""Sonst sprengt jedes Kommando die Wortgrenze."""
|
||||
lang = '- Befehl "uv run python -m tft.cli refresh" ausführen'
|
||||
assert _pruefe("funktion", "testen", lang) == []
|
||||
# Ohne Zitat greift die Grenze weiter
|
||||
assert _probleme(_pruefe("funktion", "testen",
|
||||
"- Ein sehr langer Schritt mit deutlich zu vielen Wörtern")) \
|
||||
== ["Mehr als 8 Wörter"]
|
||||
|
||||
|
||||
def test_schraegstrich_im_zitat_ist_erlaubt():
|
||||
assert _pruefe("funktion", "testen", '- Befehl "npm run build/dev" ausführen') == []
|
||||
assert _probleme(_pruefe("funktion", "regeln", "- Gilt für Bank und/oder Brett")) \
|
||||
== ["Klammer oder Schrägstrich"]
|
||||
|
||||
|
||||
def test_fuellwort_im_zitat_bleibt_stehen():
|
||||
"""Der Menüeintrag heißt so — gestrichen zeigte der Schritt auf nichts."""
|
||||
assert _pruefe("funktion", "testen", '- Klick auf "Auch Vorlagen zeigen"') == []
|
||||
|
||||
|
||||
def test_kommandoschritt_ist_eine_handlung():
|
||||
"""Nach dem Ergebnis darf keine Handlung mehr stehen — auch keine mit Kommando."""
|
||||
zwei = ('- Befehl "make install" ausführen\n- Anwendung installiert\n'
|
||||
'- Befehl "make test" ausführen')
|
||||
assert _probleme(_pruefe("funktion", "testen", zwei)) == \
|
||||
["Zweiter Ablauf in einer Funktion"]
|
||||
|
||||
|
||||
def test_ausloeser_ist_kein_funktionstitel():
|
||||
"""Der Titel nennt die Wirkung; der Griff steht in den Testschritten."""
|
||||
for titel in ('Befehl "make install" ausführen', "LMB auf Speichern drücken",
|
||||
"Klick auf Anlegen ausführen"):
|
||||
assert "Auslöser statt Wirkung im Titel" in _probleme(
|
||||
_pruefe("funktion", "titel", titel)), titel
|
||||
assert _pruefe("funktion", "titel", "Anwendung installieren") == []
|
||||
|
||||
|
||||
def test_vorbedingung_ist_kein_zweiter_ablauf():
|
||||
"""Der Katalog erlaubt eine Vorbedingung zuerst — sie ist kein Endzustand."""
|
||||
text = "- Badge ist sichtbar\n- RMB auf Badge\n- Text ändern\n- Neuer Text sichtbar"
|
||||
assert _pruefe("funktion", "testen", text) == []
|
||||
|
||||
|
||||
def test_zweiter_ablauf_faellt_weiter_auf():
|
||||
text = "- Karte öffnen\n- Karte sichtbar\n- Karte schließen"
|
||||
assert _probleme(_pruefe("funktion", "testen", text)) \
|
||||
== ["Zweiter Ablauf in einer Funktion"]
|
||||
|
||||
75
backend/verzeichnis.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""Das Arbeitsverzeichnis eines Projekts — dort implementiert der Agent.
|
||||
|
||||
Der Pfad liegt als eine Zeile im Projektordner und wandert beim Umbenennen mit.
|
||||
Er ist eine Eigenschaft des Projekts, nicht der Planung: gelesen und geschrieben
|
||||
wird immer im Projektstand, damit ein Planungsabbruch ihn nicht mitnimmt.
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import projekte
|
||||
|
||||
DATEI = ".verzeichnis"
|
||||
|
||||
|
||||
def _pfad(projekt: str):
|
||||
return projekte.stand(projekt) / DATEI
|
||||
|
||||
|
||||
def lies(projekt: str) -> str:
|
||||
"""Der eingestellte Pfad, oder leer."""
|
||||
try:
|
||||
return _pfad(projekt).read_text().strip()
|
||||
except OSError:
|
||||
return ""
|
||||
|
||||
|
||||
def pruefe(pfad: str) -> Path:
|
||||
"""Taugt der Pfad als Arbeitsverzeichnis? Gibt ihn aufgelöst zurück oder wirft."""
|
||||
pfad = (pfad or "").strip()
|
||||
if not pfad:
|
||||
raise ValueError("Kein Pfad angegeben")
|
||||
ziel = Path(os.path.expanduser(pfad))
|
||||
if not ziel.is_absolute():
|
||||
raise ValueError("Der Pfad muss absolut sein")
|
||||
ziel = ziel.resolve()
|
||||
if not ziel.is_dir():
|
||||
raise FileNotFoundError(f"„{ziel}“ ist kein Verzeichnis")
|
||||
if ziel == Path(ziel.anchor) or ziel == Path.home():
|
||||
# Die Wurzel oder das ganze Heimatverzeichnis ist immer ein Fehlgriff
|
||||
raise ValueError("Bitte ein Projektverzeichnis wählen, nicht die Wurzel")
|
||||
return ziel
|
||||
|
||||
|
||||
def setze(projekt: str, pfad: str) -> str:
|
||||
ziel = pruefe(pfad)
|
||||
_pfad(projekt).write_text(f"{ziel}\n")
|
||||
return str(ziel)
|
||||
|
||||
|
||||
def loesche(projekt: str):
|
||||
_pfad(projekt).unlink(missing_ok=True)
|
||||
|
||||
|
||||
def ordner(pfad: str = "") -> dict:
|
||||
"""Ein Verzeichnis zum Durchblättern: Unterordner, ohne Verstecktes.
|
||||
|
||||
Kein Pfad heißt Heimatverzeichnis — dort beginnt die Suche. Die Auswahl
|
||||
trifft der Mensch; hier wird nur gelistet, nie geschrieben.
|
||||
"""
|
||||
ziel = Path(os.path.expanduser(pfad.strip())) if pfad.strip() else Path.home()
|
||||
if not ziel.is_absolute():
|
||||
raise ValueError("Der Pfad muss absolut sein")
|
||||
ziel = ziel.resolve()
|
||||
if not ziel.is_dir():
|
||||
raise FileNotFoundError(f"„{ziel}“ ist kein Verzeichnis")
|
||||
try:
|
||||
unter = sorted(
|
||||
(e.name for e in ziel.iterdir()
|
||||
if e.is_dir() and not e.name.startswith(".")),
|
||||
key=str.lower)
|
||||
except PermissionError:
|
||||
raise ValueError(f"„{ziel}“ ist nicht lesbar")
|
||||
eltern = str(ziel.parent) if ziel.parent != ziel else ""
|
||||
return {"pfad": str(ziel), "eltern": eltern, "ordner": unter}
|
||||
122
daten/DesktopNote/.chat.json
Normal file
@@ -0,0 +1,122 @@
|
||||
[
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "Wie wird die Anwendung auf dem PC ausgeführt?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Ich weiß nicht, wie die Anwendung gestartet wird. Eine übliche Variante für Ubuntu wäre ein Icon im System Tray, das bei Klick auf das Icon die Topbar öffnet. Soll ich eine Karte dafür anlegen?"
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "Nein es soll automatisch gestartet werden"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Entwurf für die Karte. Der Autostart ist kern, weil ohne ihn das Badge nie erscheint, wenn der Benutzer es erwartet."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "Braucht autostart nicht sowas wie ein Makefile oder so, dass einmal ausgeführt wird und die anwendung installiert?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Guter Punkt. Autostart setzt voraus, dass die Anwendung einmal installiert wird. Das ist ein eigener Schritt, kein Teil des Badges. Hier ein Entwurf für eine Installationskarte. Klärungsbedarf: Muss der Benutzer die Installation selbst durchführen, oder reicht ein Skript?"
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "ich brauche ein setup mit make commands um die anwendung; welche make commands würde sinn machen?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Die Wahl der Make-Befehle ist eine Entscheidung zur Umsetzung, nicht zum Produkt. Ich kann keine passenden Befehle vorschlagen — das ist bei jeder Technologie anders und hängt davon ab, was die Installation umfasst. Wenn du weißt, welche Befehle du brauchst, nenne sie mir. Ich dokumentiere, wie man sie aufruft."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "ich brauche ein setup mit make commands um die anwendung; welche make commands würde sinn machen?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Ich schlage zwei übliche Make-Befehle vor, die zu fast jedem Projekt passen: \"make install\" für die Erstinstallation und \"make uninstall\" zum Entfernen. \"make\" ohne Ziel zeigt eine Hilfe an. Das sind Konventionen — wenn etwas anderes besser passt, sag Bescheid."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "das badge soll eine weitere funktion bekommen; ich will mehrere kurze setze eingaben können; ein satz je zeile; dann kann ich bestimmen welcher satz angezeigt wird; oder ich kann einen idle setzen, dann wechselt der satz alle x Stunden"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Die Karte Badge wird um zwei Funktionen erweitert: Eintrag auswählen und Idle-Modus aktivieren. Einträge sind Zeilen in der Textarea, aus denen man einen zum Anzeigen wählt. Der Idle-Modus wechselt automatisch alle eingestellten Stunden. Die bestehende Funktion Text anpassen bleibt als RMB-Einstiegspunkt."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "die funktionen haben teilweise keine daten"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Testschritte ergänzt. Eintrag auswählen und Idle-Modus aktivieren haben jetzt Abläufe. Die Texte sind knapp — wenn etwas fehlt, sag Bescheid."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "prüfe die karten"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Vier klare Verstöße korrigiert: die Icon-Regel, die Position „Links in der Topbar\", „Makefile im Projektroot\" als Bauweise und „Bestätigen klicken\" ohne Maustaste. Dazu heißt „Textarea\" jetzt überall „Textfeld\", das Kartenziel ist nicht mehr zirkulär, „Idle-Modus\" wurde zu „Automatischen Wechsel aktivieren\" verdeutscht. Offene Frage: gilt jede Zeile als ein Eintrag, oder trennt wirklich eine Leerzeile die Einträge — beides stand widersprüchlich auf der Karte, ich habe „Jede Zeile ist ein Eintrag\" gesetzt. Zweite Frage: wie heißt der Schalter für den automatischen Wechsel, ich habe „Automatisch wechseln\" angenommen."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "einige funktionen haben keinen inhalt"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Zwei Funktionen hatten keine Testschritte: Einträge bearbeiten und Automatischen Wechsel aktivieren. Beide sind jetzt ausgefüllt. Beim automatischen Wechsel habe ich \"Automatisch wechseln\" als Schalter und ein Feld für Stunden angenommen — stimmt das? Bei Einträge bearbeiten nehme ich an, dass RMB direkt das Textfeld öffnet und \"Bestätigen\" speichert."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "prüfe die planung"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Vier Verstöße korrigiert: \"Abbrechen\" ist jetzt zitiert, die Regel \"Jede Zeile ist ein Eintrag\" stand doppelt in den Testschritten, dem Deinstallieren fehlte die Vorbedingung, und das Setup-Ziel nannte nur die Installation. Der Endzustand bei \"Einträge bearbeiten\" heißt jetzt \"Einträge gespeichert\", weil ein zuvor gewählter Eintrag sonst überschrieben würde. Neu als Entwurf, bitte prüfen: Einträge überleben das Abmelden, und die Auswahl eines Eintrags beendet den automatischen Wechsel — sonst gibt es keinen Weg zurück. Offener Widerspruch: \"Ohne Eintrag bleibt das Badge sichtbar\" widerspricht deiner Ansage \"sichtbar, wenn ein Text definiert ist\"; ich habe sie behalten, weil man nach der Installation sonst kein Ziel für RMB hat."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "Bleiben die Einträge persistent über den Neustart hinaus?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Ja — die Regel \"Einträge bleiben nach dem Abmelden erhalten\" steht schon auf der Karte, sie deckt Abmelden und Neustart. Ich schärfe sie zu \"Einträge bleiben nach einem Neustart erhalten\", damit kein Zweifel bleibt. Offen: gilt das auch für den gewählten Eintrag und den automatischen Wechsel — laufen die nach dem Neustart weiter? Mein Entwurf nimmt Ja an und setzt je eine Regel dafür."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "okay fehlt noch etwas?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Zwei Lücken sehe ich. Erstens: welcher Eintrag erscheint ohne eigene Auswahl — mein Entwurf setzt den ersten. Zweitens: überleben gewählter Eintrag und automatischer Wechsel einen Neustart — der Entwurf nimmt Ja an und schärft die Abmelde-Regel zum Neustart. Sonst ist die Planung vollständig, Setup bleibt unverändert."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "prüfe die features auf kompaktheit"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Drei Stellen waren doppelt: die Neustart-Zusage stand dreimal, ich fasse sie als Kartenregel \"Einstellungen bleiben nach einem Neustart erhalten\" zusammen. Beim automatischen Wechsel werden Reihenfolge und Umbruch zu einer Regel \"Wechsel läuft zyklisch durch die Einträge\". Die Regel zum ersten Eintrag ist kürzer formuliert, Setup bleibt unverändert. Sag Bescheid, falls die Sammelregel dir zu grob ist — dann trenne ich Einträge, Auswahl und Wechsel wieder."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "prüfe die karten"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Setup steht auf optional, trägt aber die Installation — ohne sie läuft nichts, also kern. \"Text eingeben\" sagt nicht, wohin — jetzt \"Text in das Textfeld eingeben\". Ebenso präzisiert: \"LMB auf die Zeile im Textfeld\". Offen: erfolgt die Auswahl wirklich im Bearbeitungs-Textfeld oder in einer eigenen Liste?"
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "ich kann keinen text eintragen"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Mein Fehler in der Annahme: RMB öffnet kein Textfeld, sondern ein Menü. Entwurf: RMB auf Badge, dann Klick auf \"Einträge bearbeiten\" — erst dann kommt das Textfeld. Die Auswahl habe ich damit auf das Menü gelegt: LMB auf den Eintrag im Menü, ohne Bestätigen. Stimmen die Menüeinträge so, und ist es RMB oder öffnet LMB das Menü?"
|
||||
}
|
||||
]
|
||||
122
daten/DesktopNote/.planung/.chat.json
Normal file
@@ -0,0 +1,122 @@
|
||||
[
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "Wie wird die Anwendung auf dem PC ausgeführt?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Ich weiß nicht, wie die Anwendung gestartet wird. Eine übliche Variante für Ubuntu wäre ein Icon im System Tray, das bei Klick auf das Icon die Topbar öffnet. Soll ich eine Karte dafür anlegen?"
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "Nein es soll automatisch gestartet werden"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Entwurf für die Karte. Der Autostart ist kern, weil ohne ihn das Badge nie erscheint, wenn der Benutzer es erwartet."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "Braucht autostart nicht sowas wie ein Makefile oder so, dass einmal ausgeführt wird und die anwendung installiert?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Guter Punkt. Autostart setzt voraus, dass die Anwendung einmal installiert wird. Das ist ein eigener Schritt, kein Teil des Badges. Hier ein Entwurf für eine Installationskarte. Klärungsbedarf: Muss der Benutzer die Installation selbst durchführen, oder reicht ein Skript?"
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "ich brauche ein setup mit make commands um die anwendung; welche make commands würde sinn machen?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Die Wahl der Make-Befehle ist eine Entscheidung zur Umsetzung, nicht zum Produkt. Ich kann keine passenden Befehle vorschlagen — das ist bei jeder Technologie anders und hängt davon ab, was die Installation umfasst. Wenn du weißt, welche Befehle du brauchst, nenne sie mir. Ich dokumentiere, wie man sie aufruft."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "ich brauche ein setup mit make commands um die anwendung; welche make commands würde sinn machen?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Ich schlage zwei übliche Make-Befehle vor, die zu fast jedem Projekt passen: \"make install\" für die Erstinstallation und \"make uninstall\" zum Entfernen. \"make\" ohne Ziel zeigt eine Hilfe an. Das sind Konventionen — wenn etwas anderes besser passt, sag Bescheid."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "das badge soll eine weitere funktion bekommen; ich will mehrere kurze setze eingaben können; ein satz je zeile; dann kann ich bestimmen welcher satz angezeigt wird; oder ich kann einen idle setzen, dann wechselt der satz alle x Stunden"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Die Karte Badge wird um zwei Funktionen erweitert: Eintrag auswählen und Idle-Modus aktivieren. Einträge sind Zeilen in der Textarea, aus denen man einen zum Anzeigen wählt. Der Idle-Modus wechselt automatisch alle eingestellten Stunden. Die bestehende Funktion Text anpassen bleibt als RMB-Einstiegspunkt."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "die funktionen haben teilweise keine daten"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Testschritte ergänzt. Eintrag auswählen und Idle-Modus aktivieren haben jetzt Abläufe. Die Texte sind knapp — wenn etwas fehlt, sag Bescheid."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "prüfe die karten"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Vier klare Verstöße korrigiert: die Icon-Regel, die Position „Links in der Topbar\", „Makefile im Projektroot\" als Bauweise und „Bestätigen klicken\" ohne Maustaste. Dazu heißt „Textarea\" jetzt überall „Textfeld\", das Kartenziel ist nicht mehr zirkulär, „Idle-Modus\" wurde zu „Automatischen Wechsel aktivieren\" verdeutscht. Offene Frage: gilt jede Zeile als ein Eintrag, oder trennt wirklich eine Leerzeile die Einträge — beides stand widersprüchlich auf der Karte, ich habe „Jede Zeile ist ein Eintrag\" gesetzt. Zweite Frage: wie heißt der Schalter für den automatischen Wechsel, ich habe „Automatisch wechseln\" angenommen."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "einige funktionen haben keinen inhalt"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Zwei Funktionen hatten keine Testschritte: Einträge bearbeiten und Automatischen Wechsel aktivieren. Beide sind jetzt ausgefüllt. Beim automatischen Wechsel habe ich \"Automatisch wechseln\" als Schalter und ein Feld für Stunden angenommen — stimmt das? Bei Einträge bearbeiten nehme ich an, dass RMB direkt das Textfeld öffnet und \"Bestätigen\" speichert."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "prüfe die planung"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Vier Verstöße korrigiert: \"Abbrechen\" ist jetzt zitiert, die Regel \"Jede Zeile ist ein Eintrag\" stand doppelt in den Testschritten, dem Deinstallieren fehlte die Vorbedingung, und das Setup-Ziel nannte nur die Installation. Der Endzustand bei \"Einträge bearbeiten\" heißt jetzt \"Einträge gespeichert\", weil ein zuvor gewählter Eintrag sonst überschrieben würde. Neu als Entwurf, bitte prüfen: Einträge überleben das Abmelden, und die Auswahl eines Eintrags beendet den automatischen Wechsel — sonst gibt es keinen Weg zurück. Offener Widerspruch: \"Ohne Eintrag bleibt das Badge sichtbar\" widerspricht deiner Ansage \"sichtbar, wenn ein Text definiert ist\"; ich habe sie behalten, weil man nach der Installation sonst kein Ziel für RMB hat."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "Bleiben die Einträge persistent über den Neustart hinaus?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Ja — die Regel \"Einträge bleiben nach dem Abmelden erhalten\" steht schon auf der Karte, sie deckt Abmelden und Neustart. Ich schärfe sie zu \"Einträge bleiben nach einem Neustart erhalten\", damit kein Zweifel bleibt. Offen: gilt das auch für den gewählten Eintrag und den automatischen Wechsel — laufen die nach dem Neustart weiter? Mein Entwurf nimmt Ja an und setzt je eine Regel dafür."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "okay fehlt noch etwas?"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Zwei Lücken sehe ich. Erstens: welcher Eintrag erscheint ohne eigene Auswahl — mein Entwurf setzt den ersten. Zweitens: überleben gewählter Eintrag und automatischer Wechsel einen Neustart — der Entwurf nimmt Ja an und schärft die Abmelde-Regel zum Neustart. Sonst ist die Planung vollständig, Setup bleibt unverändert."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "prüfe die features auf kompaktheit"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Drei Stellen waren doppelt: die Neustart-Zusage stand dreimal, ich fasse sie als Kartenregel \"Einstellungen bleiben nach einem Neustart erhalten\" zusammen. Beim automatischen Wechsel werden Reihenfolge und Umbruch zu einer Regel \"Wechsel läuft zyklisch durch die Einträge\". Die Regel zum ersten Eintrag ist kürzer formuliert, Setup bleibt unverändert. Sag Bescheid, falls die Sammelregel dir zu grob ist — dann trenne ich Einträge, Auswahl und Wechsel wieder."
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "prüfe die karten"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Setup steht auf optional, trägt aber die Installation — ohne sie läuft nichts, also kern. \"Text eingeben\" sagt nicht, wohin — jetzt \"Text in das Textfeld eingeben\". Ebenso präzisiert: \"LMB auf die Zeile im Textfeld\". Offen: erfolgt die Auswahl wirklich im Bearbeitungs-Textfeld oder in einer eigenen Liste?"
|
||||
},
|
||||
{
|
||||
"rolle": "person",
|
||||
"text": "ich kann keinen text eintragen"
|
||||
},
|
||||
{
|
||||
"rolle": "ki",
|
||||
"text": "Mein Fehler in der Annahme: RMB öffnet kein Textfeld, sondern ein Menü. Entwurf: RMB auf Badge, dann Klick auf \"Einträge bearbeiten\" — erst dann kommt das Textfeld. Die Auswahl habe ich damit auf das Menü gelegt: LMB auf den Eintrag im Menü, ohne Bestätigen. Stimmen die Menüeinträge so, und ist es RMB oder öffnet LMB das Menü?"
|
||||
}
|
||||
]
|
||||
50
daten/DesktopNote/.planung/badge.md
Normal file
@@ -0,0 +1,50 @@
|
||||
<!-- titel -->
|
||||
Badge
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Zeigt einen von mehreren Einträgen in der Topbar an
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ohne Eintrag bleibt das Badge sichtbar
|
||||
- Beliebige Schriftzeichen erlaubt
|
||||
- Jede Zeile ist ein Eintrag
|
||||
- Ohne Auswahl erscheint der erste Eintrag
|
||||
- Einstellungen bleiben nach einem Neustart erhalten
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Einträge bearbeiten
|
||||
<!-- regeln -->
|
||||
- Textfeld zeigt die vorhandenen Einträge
|
||||
- "Abbrechen" verwirft die Änderung
|
||||
<!-- testen -->
|
||||
- RMB auf Badge
|
||||
- Klick auf "Einträge bearbeiten"
|
||||
- Text in das Textfeld eingeben
|
||||
- LMB auf "Bestätigen"
|
||||
- Einträge gespeichert
|
||||
<!-- funktion -->
|
||||
Eintrag auswählen
|
||||
<!-- regeln -->
|
||||
- Menü listet alle Einträge
|
||||
<!-- testen -->
|
||||
- Mehrere Einträge vorhanden
|
||||
- RMB auf Badge
|
||||
- LMB auf den Eintrag im Menü
|
||||
- Gewählter Eintrag im Badge
|
||||
<!-- funktion -->
|
||||
Automatischen Wechsel aktivieren
|
||||
<!-- ziel -->
|
||||
Zeigt die Einträge ohne Zutun nacheinander
|
||||
<!-- regeln -->
|
||||
- Wechsel läuft zyklisch durch die Einträge
|
||||
- Auswahl eines Eintrags beendet den Wechsel
|
||||
<!-- testen -->
|
||||
- Mehrere Einträge vorhanden
|
||||
- RMB auf Badge
|
||||
- Klick auf "Automatisch wechseln"
|
||||
- Stunden bis zum Wechsel eingeben
|
||||
- LMB auf "Bestätigen"
|
||||
- Badge wechselt nach der eingestellten Zeit
|
||||
25
daten/DesktopNote/.planung/setup.md
Normal file
@@ -0,0 +1,25 @@
|
||||
<!-- titel -->
|
||||
Setup
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Bringt die Anwendung auf den Rechner und entfernt sie wieder
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Befehl "make" zeigt die Hilfe
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anwendung installieren
|
||||
<!-- testen -->
|
||||
- Befehl "make install" ausführen
|
||||
- Abmelden und wieder anmelden
|
||||
- Badge in der Topbar sichtbar
|
||||
<!-- funktion -->
|
||||
Anwendung deinstallieren
|
||||
<!-- testen -->
|
||||
- Anwendung installiert
|
||||
- Befehl "make uninstall" ausführen
|
||||
- Abmelden und wieder anmelden
|
||||
- Badge fehlt in der Topbar
|
||||
13
daten/DesktopNote/.planung/vision.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- titel -->
|
||||
Vision
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
vision
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Text in der Topbar vom Ubuntu Desktop anzeigen.
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Stop trying to get rich, start trying to follow the rules
|
||||
- Stop act like a person, become that person
|
||||
- Discipline is the game
|
||||
50
daten/DesktopNote/badge.md
Normal file
@@ -0,0 +1,50 @@
|
||||
<!-- titel -->
|
||||
Badge
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Zeigt einen von mehreren Einträgen in der Topbar an
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ohne Eintrag bleibt das Badge sichtbar
|
||||
- Beliebige Schriftzeichen erlaubt
|
||||
- Jede Zeile ist ein Eintrag
|
||||
- Ohne Auswahl erscheint der erste Eintrag
|
||||
- Einstellungen bleiben nach einem Neustart erhalten
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Einträge bearbeiten
|
||||
<!-- regeln -->
|
||||
- Textfeld zeigt die vorhandenen Einträge
|
||||
- "Abbrechen" verwirft die Änderung
|
||||
<!-- testen -->
|
||||
- RMB auf Badge
|
||||
- Klick auf "Einträge bearbeiten"
|
||||
- Text in das Textfeld eingeben
|
||||
- LMB auf "Bestätigen"
|
||||
- Einträge gespeichert
|
||||
<!-- funktion -->
|
||||
Eintrag auswählen
|
||||
<!-- regeln -->
|
||||
- Menü listet alle Einträge
|
||||
<!-- testen -->
|
||||
- Mehrere Einträge vorhanden
|
||||
- RMB auf Badge
|
||||
- LMB auf den Eintrag im Menü
|
||||
- Gewählter Eintrag im Badge
|
||||
<!-- funktion -->
|
||||
Automatischen Wechsel aktivieren
|
||||
<!-- ziel -->
|
||||
Zeigt die Einträge ohne Zutun nacheinander
|
||||
<!-- regeln -->
|
||||
- Wechsel läuft zyklisch durch die Einträge
|
||||
- Auswahl eines Eintrags beendet den Wechsel
|
||||
<!-- testen -->
|
||||
- Mehrere Einträge vorhanden
|
||||
- RMB auf Badge
|
||||
- Klick auf "Automatisch wechseln"
|
||||
- Stunden bis zum Wechsel eingeben
|
||||
- LMB auf "Bestätigen"
|
||||
- Badge wechselt nach der eingestellten Zeit
|
||||
25
daten/DesktopNote/setup.md
Normal file
@@ -0,0 +1,25 @@
|
||||
<!-- titel -->
|
||||
Setup
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Bringt die Anwendung auf den Rechner und entfernt sie wieder
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Befehl "make" zeigt die Hilfe
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anwendung installieren
|
||||
<!-- testen -->
|
||||
- Befehl "make install" ausführen
|
||||
- Abmelden und wieder anmelden
|
||||
- Badge in der Topbar sichtbar
|
||||
<!-- funktion -->
|
||||
Anwendung deinstallieren
|
||||
<!-- testen -->
|
||||
- Anwendung installiert
|
||||
- Befehl "make uninstall" ausführen
|
||||
- Abmelden und wieder anmelden
|
||||
- Badge fehlt in der Topbar
|
||||
13
daten/DesktopNote/vision.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- titel -->
|
||||
Vision
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
vision
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Text in der Topbar vom Ubuntu Desktop anzeigen.
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Stop trying to get rich, start trying to follow the rules
|
||||
- Stop act like a person, become that person
|
||||
- Discipline is the game
|
||||
1
daten/MtoRagSystem/.planung/.verzeichnis
Normal file
@@ -0,0 +1 @@
|
||||
/home/arbeit/arbeit/MtoRagSystem
|
||||
157
daten/MtoRagSystem/.planung/anbindung.md
Normal file
@@ -0,0 +1,157 @@
|
||||
<!-- titel -->
|
||||
Anbindung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Bindet einen externen Server kontrolliert an
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein Token wird nie gespeichert, nur sein Name
|
||||
- Eine Anbindung startet eingeschaltet, ohne Chatfreigabe
|
||||
- Eine Anbindung wirkt erst nach Freigabe
|
||||
- Ein Import führt nie ein Werkzeug aus
|
||||
- Ein Import liest keine Inhalte
|
||||
- Anweisungen fremder Inhalte werden entfernt
|
||||
- Ein Transport über Standardeingabe ist gesperrt
|
||||
- Nur verschlüsselte Verbindungen sind erlaubt
|
||||
- Interne Netze sind gesperrt
|
||||
- Weiterleitungen werden nicht verfolgt
|
||||
- Protokolle enthalten nur Metadaten
|
||||
- Der Bereich braucht die höchste Rolle
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung anlegen
|
||||
<!-- regeln -->
|
||||
- Speichern folgt einer bestandenen Prüfung
|
||||
- Ein Speichern ändert keine Antwort
|
||||
- Ein Formulartoken ist Pflicht
|
||||
<!-- testen -->
|
||||
- Menüeintrag MCP Quellen wählen
|
||||
- Reiter Anbindung anlegen wählen
|
||||
- Formular ausfüllen
|
||||
- Anbindung speichern
|
||||
- Anbindung in der Übersicht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung prüfen
|
||||
<!-- ziel -->
|
||||
Testet die Angaben gegen Erlaubnisliste und Regeln
|
||||
<!-- regeln -->
|
||||
- Ohne Onlinetest entstehen keine Abrufe
|
||||
- Das Ergebnis nennt den Grund
|
||||
- Die Prüfung speichert nicht
|
||||
<!-- testen -->
|
||||
- Formular ausfüllen
|
||||
- LMB auf Anbindung prüfen
|
||||
- Prüfergebnis mit Begründung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung bearbeiten
|
||||
<!-- regeln -->
|
||||
- Änderungen wirken erst nach dem Speichern
|
||||
- Werkzeugdaten bleiben erhalten
|
||||
- Zugewiesene Inhalte bleiben am Kurznamen gebunden
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Bearbeiten
|
||||
- Formular vorbefüllt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung umschalten
|
||||
<!-- ziel -->
|
||||
Legt eine Anbindung vorübergehend still
|
||||
<!-- regeln -->
|
||||
- Ausgewählte Inhalte bleiben gespeichert
|
||||
- Eine stillgelegte Anbindung wirkt nicht
|
||||
- Wiedereinschalten braucht keine neue Freigabe
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Deaktivieren
|
||||
- Zustandsmarke wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung entfernen
|
||||
<!-- regeln -->
|
||||
- Der Raum wird zuvor abgeschaltet
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Entfernen
|
||||
- Bestätigen
|
||||
- Anbindung verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Ressource übernehmen
|
||||
<!-- ziel -->
|
||||
Schreibt eine gefundene Ressource in die Anbindung
|
||||
<!-- regeln -->
|
||||
- Nur erkannte Ressourcen sind übernehmbar
|
||||
- Die Übernahme schaltet den Chat nicht ein
|
||||
<!-- testen -->
|
||||
- Serverinhalte aktualisieren
|
||||
- LMB auf Ressource übernehmen
|
||||
- Ressource in der Anbindung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Serverinhalte aktualisieren
|
||||
<!-- ziel -->
|
||||
Erkennt Ressourcen, Werkzeuge und Vorlagen als Metadaten
|
||||
<!-- regeln -->
|
||||
- Kein Werkzeug wird ausgeführt
|
||||
- Vorlagen werden erkannt, nie ausgeführt
|
||||
- Ressourcen werden nicht gelesen
|
||||
- Gefundene Werkzeuge sind zunächst gesperrt
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Inhalte aktualisieren
|
||||
- Gefundene Inhalte sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung online prüfen
|
||||
<!-- ziel -->
|
||||
Prüft eine gespeicherte Anbindung im Terminal
|
||||
<!-- regeln -->
|
||||
- Geprüft werden Freigabe und ein Inhalt
|
||||
- Ohne prüfbaren Inhalt bricht der Lauf ab
|
||||
- Ein fehlendes Geheimnis blockt vorher
|
||||
- Anfragen werden bereinigt protokolliert
|
||||
<!-- testen -->
|
||||
- Kommando mit Servernamen aufrufen
|
||||
- Prüfbericht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Schutzregeln ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt Grenzen und Systemprüfung der Anbindungen
|
||||
<!-- regeln -->
|
||||
- Die Anzeige ruft nichts extern ab
|
||||
- Freie Werkzeugnutzung ist gesperrt
|
||||
<!-- testen -->
|
||||
- Menüeintrag Quellen wählen
|
||||
- Reiter Sicherheit wählen
|
||||
- Grenzen und Prüfstand sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Freigaben prüfen
|
||||
<!-- ziel -->
|
||||
Prüft die Serverliste der Grundeinstellung
|
||||
<!-- regeln -->
|
||||
- Kein Transport wird geöffnet
|
||||
- Das Ergebnis nennt Server, Fehler und Warnungen
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Prüfstand je Regel sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Brücke trocken testen
|
||||
<!-- ziel -->
|
||||
Prüft Bereinigung und Belegbrücke ohne Serverkontakt
|
||||
<!-- regeln -->
|
||||
- Nur lokale Nutzlasten werden geprüft
|
||||
- Kein Transport, keine Chatwirkung
|
||||
- Fremde Anweisungsmarker fallen weg
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Bereinigte Nutzlast sichtbar
|
||||
115
daten/MtoRagSystem/.planung/antwort.md
Normal file
@@ -0,0 +1,115 @@
|
||||
<!-- titel -->
|
||||
Antwort
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Beantwortet eine Frage aus geprüften Quellen
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Nur Aussagen aus den Quellen
|
||||
- Fehlende Werte werden nicht erfunden
|
||||
- Keine Schätzung ersetzt einen fehlenden Wert
|
||||
- Fakten und Ableitungen bleiben getrennt
|
||||
- Ableitungen sind als solche markiert
|
||||
- Eignung gilt als belegpflichtige Aussage
|
||||
- Negativaussagen brauchen einen Quellenbeleg
|
||||
- Werbesprache ist untersagt
|
||||
- Sprache der Frage gilt für die Antwort
|
||||
- Interne Belegkennungen bleiben auf Nachfrage beschränkt
|
||||
- Interne Denktexte erreichen niemanden
|
||||
- Die genutzte Datenbasis steht an der Antwort
|
||||
- Trefferzahl aus Wissen und Shop liegt bei
|
||||
- Die Antwortdauer wird ausgewiesen
|
||||
- Ein Vertrauensabzeichen steht an der Antwort
|
||||
- Wiederholungsschleifen werden sichtbar abgeschnitten
|
||||
- Transparente Unsicherheit schlägt sichere Falschaussage
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Frage stellen
|
||||
<!-- ziel -->
|
||||
Sendet eine Frage und empfängt die Antwort laufend
|
||||
<!-- regeln -->
|
||||
- Leere Frage wird abgewiesen
|
||||
- Höchstens 10000 Zeichen
|
||||
- Warnung ab 7500 Zeichen
|
||||
- Erneutes Senden bleibt bis zum Ende gesperrt
|
||||
- Entwurf überlebt einen Neuladen
|
||||
- Unterbrochener Empfang wird fortgesetzt
|
||||
- Ein Lauf verfällt nach 900 Sekunden
|
||||
- Ein stehender Lauf wird beendet
|
||||
<!-- testen -->
|
||||
- Text eingeben
|
||||
- Enter drücken
|
||||
- Frage im Verlauf
|
||||
- Antwort läuft ein
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Antwort abbrechen
|
||||
<!-- ziel -->
|
||||
Beendet eine laufende Antwort vorzeitig
|
||||
<!-- regeln -->
|
||||
- Nur während des Empfangs möglich
|
||||
- Der Serverlauf arbeitet weiter
|
||||
- Der Vermerk gilt nur in der laufenden Ansicht
|
||||
- Nach dem Neuladen steht die volle Antwort
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf Abbrechen
|
||||
- Abbruchvermerk im Verlauf
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Frage erneut senden
|
||||
<!-- ziel -->
|
||||
Wiederholt die Frage mit anderer Einstellung
|
||||
<!-- regeln -->
|
||||
- Angeboten sind nur ungenutzte Varianten
|
||||
- Der Klick setzt die Einstellung passend
|
||||
- Während des Empfangs gesperrt
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf eine Variante
|
||||
- Frage erneut im Verlauf
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Antwortmodus wählen
|
||||
<!-- ziel -->
|
||||
Wählt zwischen gründlicher und schneller Antwort
|
||||
<!-- regeln -->
|
||||
- Zwei Werte: Standard und schnell
|
||||
- Ungültiger Wert fällt auf Standard
|
||||
- Der schnelle Modus nutzt ein anderes Modell
|
||||
- Der schnelle Modus antwortet ungenauer
|
||||
- Die Wahl gilt für die ganze Unterhaltung
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Antwortmodus wählen
|
||||
- Modus an der nächsten Antwort
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Datenbasis wählen
|
||||
<!-- ziel -->
|
||||
Legt fest, ob Wissen oder Shopdaten zählen
|
||||
<!-- regeln -->
|
||||
- Vier Werte: automatisch, Wissen, Shop, beides
|
||||
- Unbekannter Wert fällt auf automatisch
|
||||
- Nur Wissen löst keine Shopsuche aus
|
||||
- Die genutzte Basis steht in der Antwort
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Datenbasis wählen
|
||||
- Basis in der Zusammenfassung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Folgeaktion auslösen
|
||||
<!-- ziel -->
|
||||
Sendet eine vorgeschlagene Folgefrage sofort
|
||||
<!-- regeln -->
|
||||
- Der Fragetext kommt vom Server
|
||||
- Angebot entfällt bei ablehnender Antwort
|
||||
- Während des Empfangs passiert nichts
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf eine Folgeaktion
|
||||
- Folgefrage im Verlauf
|
||||
85
daten/MtoRagSystem/.planung/auftrag.md
Normal file
@@ -0,0 +1,85 @@
|
||||
<!-- titel -->
|
||||
Auftrag
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Führt Indexierung und Neuaufbau nachvollziehbar aus
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Jeder Lauf hinterlässt einen Auftrag
|
||||
- Der Auftrag nennt Typ, Zustand, Zeiten und Person
|
||||
- Fünf Zustände bis zum Abbruch
|
||||
- Nur der Neuaufbau schreibt eine Protokolldatei
|
||||
- Nur ein Indexlauf läuft gleichzeitig
|
||||
- Ein Strukturwechsel erzwingt einen sichtbaren Neuaufbau
|
||||
- Ein unvollständiger Aufbau bricht ab
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Aufträge einsehen
|
||||
<!-- ziel -->
|
||||
Zeigt den Verlauf aller Indexläufe
|
||||
<!-- regeln -->
|
||||
- Neueste Aufträge stehen oben
|
||||
- Der Fehlertext endet in der Liste bei 120 Zeichen
|
||||
<!-- testen -->
|
||||
- Menüeintrag Aufträge wählen
|
||||
- Auftragsliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Auftrag verfolgen
|
||||
<!-- ziel -->
|
||||
Beobachtet einen einzelnen Lauf bis zum Ende
|
||||
<!-- regeln -->
|
||||
- Die Kennung muss dem Kennungsformat folgen
|
||||
- Der Stand wird zweisekündlich nachgeladen
|
||||
- Geliefert werden Typ, Zustand, Zeiten und Fehler
|
||||
- Das Nachladen endet mit dem Auftrag
|
||||
<!-- testen -->
|
||||
- Auftragsliste öffnen
|
||||
- LMB auf eine Kennung
|
||||
- Zustandsmarke wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Index neu aufbauen
|
||||
<!-- ziel -->
|
||||
Überführt vorgemerkte Änderungen in den Index
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf starten
|
||||
- Der Auftrag beginnt wartend
|
||||
- Die Arbeit läuft im Hintergrund
|
||||
- Ein Fehlstart markiert den Auftrag als gescheitert
|
||||
- Nach Erfolg wird der Zwischenspeicher geleert
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- LMB auf Index neu aufbauen
|
||||
- Bestätigen
|
||||
- Auftragsseite sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Auftrag ausführen
|
||||
<!-- ziel -->
|
||||
Startet einen vorhandenen Auftrag im Terminal
|
||||
<!-- regeln -->
|
||||
- Unbekannte Kennung wird abgewiesen
|
||||
- Abgeschlossene Aufträge laufen nicht erneut
|
||||
- Ein Trockenlauf vermeidet schwere Schritte
|
||||
<!-- testen -->
|
||||
- Kommando mit Kennung aufrufen
|
||||
- Zustandszeile sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Index hart neu aufbauen
|
||||
<!-- ziel -->
|
||||
Baut Chunks, Vektoren und Tags vollständig neu
|
||||
<!-- regeln -->
|
||||
- Ohne Erzwingen bricht der Lauf ab
|
||||
- Vier Schritte laufen in fester Reihenfolge
|
||||
- Einzelne Schritte lassen sich überspringen
|
||||
- Ein gescheiterter Schritt beendet den Lauf
|
||||
- Ein Trockenlauf schreibt keine Indexdatei
|
||||
<!-- testen -->
|
||||
- Kommando mit Erzwingen aufrufen
|
||||
- Vier Schritte sichtbar
|
||||
- Gesundheitsstand am Ende
|
||||
118
daten/MtoRagSystem/.planung/batch.md
Normal file
@@ -0,0 +1,118 @@
|
||||
<!-- titel -->
|
||||
Batch
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Importiert viele Dokumente in einem Lauf
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Höchstens 250 Dateien je Upload
|
||||
- Erlaubt sind PDF, Text, Markdown und Word
|
||||
- Geschützte PDF gelten als nicht verarbeitbar
|
||||
- Doppelte Prüfsummen werden übersprungen
|
||||
- Höchstens ein Neuaufbau je Lauf
|
||||
- Ohne Indexwirkung entfällt der Neuaufbau
|
||||
- Der Eingang wird nach dem Lauf geräumt
|
||||
- Je gelungener Lauf entsteht ein Bericht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Batch hochladen
|
||||
<!-- ziel -->
|
||||
Lädt viele Dateien gesammelt und verarbeitet sie
|
||||
<!-- regeln -->
|
||||
- Ohne Datei bricht der Lauf ab
|
||||
- Titel entstehen aus Dateinamen oder Manifest
|
||||
- Schwache Titel werden markiert
|
||||
- Wissenskarten entstehen nur auf Wunsch
|
||||
- Aktivierung ohne Wissenskarte wird verworfen
|
||||
<!-- testen -->
|
||||
- Menüeintrag Batch wählen
|
||||
- Dateien wählen
|
||||
- Batch starten
|
||||
- Ergebniszahlen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Batch vorab prüfen
|
||||
<!-- ziel -->
|
||||
Prüft einen Eingang ohne jede Schreibwirkung
|
||||
<!-- regeln -->
|
||||
- Kein Dokument wird importiert
|
||||
- Kein Modell wird aufgerufen
|
||||
- Dateityp, Prüfsumme und Dubletten werden geprüft
|
||||
- Zusatzschalter erzeugen eine Warnung
|
||||
<!-- testen -->
|
||||
- Kommando im Trockenlauf aufrufen
|
||||
- Bericht mit Dateiliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Batch importieren
|
||||
<!-- ziel -->
|
||||
Importiert einen Eingang im Terminal
|
||||
<!-- regeln -->
|
||||
- Der Import ist über Prüfsummen wiederholbar
|
||||
- Ohne eindeutigen Benutzer bricht der Lauf ab
|
||||
- Der Kommandolauf hat keine Dateigrenze
|
||||
- Erfolgreiche Quellen verlassen den Eingang
|
||||
- Fehler und Übersprungenes landen getrennt
|
||||
- Abgeleitete Versionen bleiben ohne Schalter inaktiv
|
||||
<!-- testen -->
|
||||
- Kommando mit Eingang aufrufen
|
||||
- Bericht als Datei geschrieben
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Berichte auflisten
|
||||
<!-- regeln -->
|
||||
- Höchstens 100 Berichte, neueste oben
|
||||
- Defekte Berichte werden übersprungen
|
||||
<!-- testen -->
|
||||
- Menüeintrag Batch wählen
|
||||
- Berichtsliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Bericht ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt einen Lauf je Datei und Schritt
|
||||
<!-- regeln -->
|
||||
- Die Kennung darf keine Sonderzeichen tragen
|
||||
- Ein unbekannter Bericht meldet einen Fehler
|
||||
- Die Ansicht startet keine Verarbeitung
|
||||
<!-- testen -->
|
||||
- Berichtsliste öffnen
|
||||
- LMB auf Anzeigen
|
||||
- Schritte und Dateien sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Bericht herunterladen
|
||||
<!-- regeln -->
|
||||
- Zwei Formate: JSON und Markdown
|
||||
- Eine fehlende Datei meldet einen Fehler
|
||||
<!-- testen -->
|
||||
- Berichtsliste öffnen
|
||||
- LMB auf ein Format
|
||||
- Datei im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Bericht löschen
|
||||
<!-- regeln -->
|
||||
- Beide Formate fallen zusammen weg
|
||||
- Dokumente und Index bleiben unberührt
|
||||
<!-- testen -->
|
||||
- Berichtsliste öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Bericht verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Eingang bereinigen
|
||||
<!-- ziel -->
|
||||
Räumt leere Ordner und falsche Ablagen auf
|
||||
<!-- regeln -->
|
||||
- Die Bereinigung wirkt nur im Importverzeichnis
|
||||
- Namenskollisionen bekommen einen Zähler
|
||||
- Kein Einfluss auf Suche oder Antwort
|
||||
<!-- testen -->
|
||||
- Menüeintrag Batch wählen
|
||||
- LMB auf Eingang bereinigen
|
||||
- Zahl geräumter Ordner sichtbar
|
||||
71
daten/MtoRagSystem/.planung/beleg.md
Normal file
@@ -0,0 +1,71 @@
|
||||
<!-- titel -->
|
||||
Beleg
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Weist nach, worauf eine Aussage sich stützt
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Belegquellen sind Wissen, Shop und URL-Inhalte
|
||||
- Frühere Antworten belegen keine Fachwerte
|
||||
- Jede Antwort erhält genau einen Belegzustand
|
||||
- Direkt belegt gilt nur bei einem tragenden Beleg
|
||||
- Verstreute Anforderungen ergeben schwach belegt
|
||||
- Fehlende Pflichtangabe ergibt nicht vollständig belegt
|
||||
- Ohne Quelle gilt nicht geprüft
|
||||
- Jeder Beleg trägt eine Stärke
|
||||
- Fehlende Pflichtmerkmale werden einzeln benannt
|
||||
- Direkte Dokumentquellen stehen unter der Antwort
|
||||
- Höchstens vier Quellentitel erscheinen
|
||||
- Eine genutzte Uploaddatei bleibt in der Quellenliste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Belegdetails aufklappen
|
||||
<!-- ziel -->
|
||||
Zeigt Prüfsignale hinter der Vertrauenslage
|
||||
<!-- regeln -->
|
||||
- Ohne echte Signale erscheint keine Belegkarte
|
||||
- Konflikte werden gesondert benannt
|
||||
- Die Anzeige gilt für alle sichtbaren Antworten
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf technische Details
|
||||
- Claims und Belege sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Zusatzinfos umschalten
|
||||
<!-- ziel -->
|
||||
Blendet Quellen und Folgeaktionen ein
|
||||
<!-- regeln -->
|
||||
- Nur genutzte Quellen werden gelistet
|
||||
- Die Einstellung überlebt einen Neuladen
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Zusatzinfos umschalten
|
||||
- Quellenblock verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Statusprotokoll einschalten
|
||||
<!-- ziel -->
|
||||
Macht Prüf- und Quellenschritte sichtbar
|
||||
<!-- regeln -->
|
||||
- Der Bereich öffnet sich beim Einschalten
|
||||
- Statusinfos stehen neben dem Verlauf
|
||||
- Fehlermeldungen bleiben immer sichtbar
|
||||
- Prompts und Geheimnisse erscheinen nie
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Statusprotokoll einschalten
|
||||
- Seitenbereich mit Zeitleiste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Statusprotokoll schließen
|
||||
<!-- regeln -->
|
||||
- Schließen schaltet die Einstellung aus
|
||||
- Der Zustand überlebt einen Neuladen
|
||||
<!-- testen -->
|
||||
- Statusprotokoll einschalten
|
||||
- LMB auf Schließen im Bereich
|
||||
- Bereich verschwindet
|
||||
82
daten/MtoRagSystem/.planung/benutzer.md
Normal file
@@ -0,0 +1,82 @@
|
||||
<!-- titel -->
|
||||
Benutzer
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Regelt Zugang und Rollen der Menschen
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein Passwort wird nur verschlüsselt gespeichert
|
||||
- Eine E-Mail ist eindeutig
|
||||
- Ein deaktiviertes Konto wird abgewiesen
|
||||
- Niemand deaktiviert sich selbst
|
||||
- Der letzte oberste Verwalter bleibt geschützt
|
||||
- Die Verwaltung braucht die höchste Rolle
|
||||
- Ein Konto lässt sich nicht löschen
|
||||
- Deaktivierung beendet die laufende Sitzung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer filtern
|
||||
<!-- regeln -->
|
||||
- Filter nach Text, Zustand und Rolle
|
||||
- Die Suche trifft Namen, E-Mail und Abteilung
|
||||
- Ein ungültiger Wert fällt auf alle
|
||||
- Die Gesamtzahlen bleiben ungefiltert
|
||||
<!-- testen -->
|
||||
- Menüeintrag Benutzer wählen
|
||||
- Filter setzen
|
||||
- LMB auf Filtern
|
||||
- Trefferzahl sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer erstellen
|
||||
<!-- regeln -->
|
||||
- Das Passwort braucht acht Zeichen
|
||||
- Die Wiederholung muss übereinstimmen
|
||||
- Mindestens eine Rolle ist Pflicht
|
||||
- Unbekannte Rollen werden abgewiesen
|
||||
- Die Grundrolle ist nicht vergebbar
|
||||
<!-- testen -->
|
||||
- Benutzerliste öffnen
|
||||
- Formular ausfüllen
|
||||
- Rollen ankreuzen
|
||||
- Erstellen
|
||||
- Benutzer in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer bearbeiten
|
||||
<!-- regeln -->
|
||||
- Leeres Passwortfeld ändert nichts
|
||||
- Die oberste Rolle entzieht sich niemand selbst
|
||||
- Namen enden bei 100 Zeichen
|
||||
- Abteilung endet bei 120 Zeichen
|
||||
<!-- testen -->
|
||||
- Benutzerliste öffnen
|
||||
- LMB auf Bearbeiten
|
||||
- Felder ändern
|
||||
- Speichern
|
||||
- Änderung in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer umschalten
|
||||
<!-- ziel -->
|
||||
Sperrt oder öffnet den Zugang sofort
|
||||
<!-- regeln -->
|
||||
- Bestehende Rollen bleiben erhalten
|
||||
<!-- testen -->
|
||||
- Benutzerliste öffnen
|
||||
- LMB auf Zustand
|
||||
- Bestätigen
|
||||
- Zustandsspalte wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer im Terminal anlegen
|
||||
<!-- regeln -->
|
||||
- Doppelte E-Mail wird abgewiesen
|
||||
- Die Eingabe erfolgt abgefragt
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Angaben eintragen
|
||||
- Benutzer angelegt
|
||||
117
daten/MtoRagSystem/.planung/betriebspruefung.md
Normal file
@@ -0,0 +1,117 @@
|
||||
<!-- titel -->
|
||||
Betriebsprüfung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Bewertet Betriebsreife vor der Abnahme
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Jede Prüfung liest nur lokale Angaben
|
||||
- Kein Chat, kein Shop, kein Modell läuft
|
||||
- Ein Fehler setzt den Gesamtstand
|
||||
- Ein fehlender Nachweis wird zur Warnung
|
||||
- Ein Nachweis wird nie stillschweigend angenommen
|
||||
- Geheimnisse bleiben Verweise
|
||||
- Der Restore-Nachweis bleibt Betreiberaufgabe
|
||||
- Das System richtet keine Zeitsteuerung ein
|
||||
- Jedes Ergebnis landet bereinigt im Protokoll
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Betrieb überblicken
|
||||
<!-- ziel -->
|
||||
Fasst alle Prüfstände und die letzte Sicherung
|
||||
<!-- regeln -->
|
||||
- Die Seite bewertet bei jedem Aufruf neu
|
||||
- Nur ausgelöste Prüfungen landen im Protokoll
|
||||
- Der nächste sinnvolle Schritt steht dabei
|
||||
<!-- testen -->
|
||||
- Menüeintrag Betrieb wählen
|
||||
- Gesamtstand und Teilstände sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherheit prüfen
|
||||
<!-- ziel -->
|
||||
Prüft Rollen, Geheimnisse und Grenzen
|
||||
<!-- regeln -->
|
||||
- Die Prüfung ersetzt kein externes Audit
|
||||
- Geheimniswerte werden nicht gelesen
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Sicherheit prüfen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherungsweg prüfen
|
||||
<!-- ziel -->
|
||||
Bewertet Pfad, Umfang und Restore-Nachweis
|
||||
<!-- regeln -->
|
||||
- Es entsteht keine Sicherung
|
||||
- Ein Restore-Erfolg wird nicht behauptet
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Sicherungsweg prüfen
|
||||
- Prüfpunkte sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Zeitsteuerung prüfen
|
||||
<!-- ziel -->
|
||||
Bewertet Automatik, Turnus und Betreibernachweise
|
||||
<!-- regeln -->
|
||||
- Der Betreiber dokumentiert Automatik selbst
|
||||
- Nicht beschreibbare Pfade erzeugen Hinweise
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Zeitsteuerung prüfen
|
||||
- Nachweistabelle sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Protokoll einsehen
|
||||
<!-- ziel -->
|
||||
Zeigt die zuletzt ausgelösten Prüfungen
|
||||
<!-- regeln -->
|
||||
- Keine Prompts und keine Rohantworten
|
||||
- Keine Geheimnisse und keine Zugangsdaten
|
||||
- Der Text endet bei 220 Zeichen
|
||||
- Höchstens 50 Einträge bleiben erhalten
|
||||
- Die Anzeige zeigt die letzten acht
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- Protokollbereich lesen
|
||||
- Letzte Prüfungen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Abnahmebericht ausgeben
|
||||
<!-- ziel -->
|
||||
Lädt den bereinigten Bericht zur Abnahme
|
||||
<!-- regeln -->
|
||||
- Zwei Formate: JSON und Markdown
|
||||
- Die Datengrenze steht im Bericht
|
||||
- Erledigte Aufgaben fallen weg
|
||||
- Der Export startet keine Prüfung
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- Format wählen
|
||||
- Bericht im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Betriebsreife im Terminal prüfen
|
||||
<!-- regeln -->
|
||||
- Nur ein grüner Stand endet ohne Fehler
|
||||
- Warnungen ändern den Ausgang nicht
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Fallliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Unterlagen öffnen
|
||||
<!-- ziel -->
|
||||
Zeigt Runbook und Checklisten im Adminbereich
|
||||
<!-- regeln -->
|
||||
- Nur Markdown aus dem Projektverzeichnis
|
||||
- Die Anzeige ist rein lesend
|
||||
<!-- testen -->
|
||||
- Menüeintrag Leitfäden wählen
|
||||
- Dokument wählen
|
||||
- Inhalt sichtbar
|
||||
51
daten/MtoRagSystem/.planung/claim.md
Normal file
@@ -0,0 +1,51 @@
|
||||
<!-- titel -->
|
||||
Claim
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Prüft einzelne Aussagen der Antwort gegen Belege
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Geprüft werden Werte, Preise und Artikelnummern
|
||||
- Geprüft werden URLs und Rollencodes
|
||||
- Geprüft werden Relationen und Kompatibilitätsaussagen
|
||||
- Ein Claim ohne Quelle gilt als unbelegt
|
||||
- Ein unbelegter Claim setzt ein Prüfsignal
|
||||
- Unbelegte Claims werden benannt
|
||||
- Höchstens fünf Beispiele erscheinen
|
||||
- Rollencodes gelten nur bei genauer Übereinstimmung
|
||||
- Relationen brauchen beide Partner in einem Dokument
|
||||
- Eine leere Antwort gilt als ungeprüft
|
||||
- Sieben Claim-Arten stehen fest
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Antwort bewerten
|
||||
<!-- ziel -->
|
||||
Meldet falsche Zuordnung oder Quellenfehler zurück
|
||||
<!-- regeln -->
|
||||
- Zwei Werte: zustimmend und ablehnend
|
||||
- Ablehnung erlaubt einen Kommentar
|
||||
- Kommentar wird auf 2000 Zeichen gekürzt
|
||||
- Bewertung braucht eine fertige Antwort
|
||||
- Eine fremde Antwort wird abgewiesen
|
||||
- Die Oberfläche sperrt nach dem Speichern
|
||||
- Ein erneuter Aufruf überschreibt die Bewertung
|
||||
- Frage und Antwort werden mitgespeichert
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf eine Bewertung
|
||||
- Bestätigung sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Prompt kopieren
|
||||
<!-- ziel -->
|
||||
Übernimmt die eigene Frage in die Zwischenablage
|
||||
<!-- regeln -->
|
||||
- Kopiert wird nur der Fragetext
|
||||
- Erfolg wird kurz gemeldet
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf Kopieren
|
||||
- Rückmeldung an der Schaltfläche
|
||||
84
daten/MtoRagSystem/.planung/diagnose.md
Normal file
@@ -0,0 +1,84 @@
|
||||
<!-- titel -->
|
||||
Diagnose
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Untersucht einzelne Teile des Antwortwegs
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Diagnosen ändern Antwortgüte und Wahrheitssicherung nicht
|
||||
- Prompts und Rohantworten werden nie ausgegeben
|
||||
- Betriebsfunktionen beeinflussen die Antwort nicht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Im Terminal fragen
|
||||
<!-- ziel -->
|
||||
Stellt Fragen an das System ohne Oberfläche
|
||||
<!-- regeln -->
|
||||
- Die Antwort läuft in Stücken ein
|
||||
- Statusmeldungen stehen dazwischen
|
||||
- Der Lauf löst echte Modellaufrufe aus
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Frage eintragen
|
||||
- Antwort läuft ein
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Suchweg testen
|
||||
<!-- ziel -->
|
||||
Prüft den hybriden Suchweg zu einer Frage
|
||||
<!-- regeln -->
|
||||
- Leere Frage wird abgewiesen
|
||||
- Die Ausgabe nennt Dauer und Trefferzahl
|
||||
<!-- testen -->
|
||||
- Kommando mit Frage aufrufen
|
||||
- Trefferliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Faktenabdeckung prüfen
|
||||
<!-- ziel -->
|
||||
Prüft, wie gut Fakten eine Frage abdecken
|
||||
<!-- regeln -->
|
||||
- Eine leere Frage wird abgewiesen
|
||||
- Eine Mindestgüte ist wählbar
|
||||
<!-- testen -->
|
||||
- Kommando mit Frage aufrufen
|
||||
- Abdeckung mit Zusammenfassung sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Ankerauflösung testen
|
||||
<!-- ziel -->
|
||||
Prüft die Auflösung einer Folgefrage trocken
|
||||
<!-- regeln -->
|
||||
- Kein Eingriff in die Laufzeit
|
||||
- Mehrdeutige Anker werden verworfen
|
||||
- Eine genannte Artikelnummer schlägt jeden Anker
|
||||
<!-- testen -->
|
||||
- Kommando mit Folgefrage aufrufen
|
||||
- Auflösungsbericht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Verlaufsanker auslesen
|
||||
<!-- ziel -->
|
||||
Zieht Bezugsanker aus einem Gesprächsverlauf
|
||||
<!-- regeln -->
|
||||
- Anker belegen keine Fachwerte
|
||||
- Eingabe per Argument, Datei oder Strom
|
||||
- Ein eingebauter Rauchtest ist wählbar
|
||||
<!-- testen -->
|
||||
- Kommando mit Rauchtest aufrufen
|
||||
- Ankerliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Fakten inspizieren
|
||||
<!-- ziel -->
|
||||
Untersucht gespeicherte Fakten der Chunkdatei
|
||||
<!-- regeln -->
|
||||
- Eine fehlende Chunkdatei meldet einen Fehler
|
||||
- Nur lesender Zugriff auf den Index
|
||||
- Filter nach Text, Typ und Anzahl
|
||||
<!-- testen -->
|
||||
- Kommando mit Suchtext aufrufen
|
||||
- Trefferliste sichtbar
|
||||
107
daten/MtoRagSystem/.planung/dokument.md
Normal file
@@ -0,0 +1,107 @@
|
||||
<!-- titel -->
|
||||
Dokument
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Führt eine Wissensquelle über ihre Versionen
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein Dokument hält mehrere Versionen
|
||||
- Genau eine Version ist aktiv
|
||||
- Tags hängen am Dokument, nicht an der Version
|
||||
- Schreiben an Dokument oder Version ändert den Index nicht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Dokumente filtern
|
||||
<!-- ziel -->
|
||||
Grenzt die Liste nach Zustand und Pflege ein
|
||||
<!-- regeln -->
|
||||
- Sechs Filter: Suche, Status, Index, Version, Titel, Tags
|
||||
- Unbekannter Filterwert fällt auf alle
|
||||
- Die Suche trifft Titel, Kennung und Dateiname
|
||||
- Kennzahlen zählen immer den Gesamtbestand
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- Filter setzen
|
||||
- LMB auf Filtern
|
||||
- Trefferzahl sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Dokument hochladen
|
||||
<!-- ziel -->
|
||||
Legt eine Wissensquelle mit erster Version an
|
||||
<!-- regeln -->
|
||||
- Die Datei ist Pflicht
|
||||
- Ohne Titel dient der Dateiname als Titel
|
||||
- Ein schwacher Titel bekommt einen Prüfhinweis
|
||||
- Version eins entsteht aktiv
|
||||
- Je Version wird eine Prüfsumme gespeichert
|
||||
- Der Index bleibt bis zum Neuaufbau unverändert
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- LMB auf neues Dokument
|
||||
- Datei wählen
|
||||
- Speichern
|
||||
- Dokumentseite sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Titel ändern
|
||||
<!-- ziel -->
|
||||
Ersetzt einen schwachen Titel fachlich
|
||||
<!-- regeln -->
|
||||
- Leerer Titel wird abgewiesen
|
||||
- Höchstens 255 Zeichen
|
||||
- Der Prüfhinweis entfällt danach
|
||||
- Index und Antwortlogik bleiben unberührt
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- Titel ändern
|
||||
- Speichern
|
||||
- Titel als geprüft markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Titel vorschlagen lassen
|
||||
<!-- ziel -->
|
||||
Erzeugt Titelkandidaten aus dem Dokumentanfang
|
||||
<!-- regeln -->
|
||||
- Der Ausschnitt endet bei 9000 Zeichen
|
||||
- Höchstens sechs Vorschläge
|
||||
- Höchstens 120 Zeichen je Vorschlag
|
||||
- Zu kurze Kandidaten fallen weg
|
||||
- Ein Klick füllt nur das Feld
|
||||
- Dokument, Version und Index bleiben unberührt
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf Titel vorschlagen
|
||||
- Kandidat wählen
|
||||
- Titelfeld gefüllt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Indexbereitschaft ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt, was den Index bisher nicht erreicht hat
|
||||
<!-- regeln -->
|
||||
- Offene Änderungen werden gezählt
|
||||
- Gelöschte Dokumente im Index werden benannt
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- Bereitschaftsblock lesen
|
||||
- Zahl offener Änderungen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Dokument löschen
|
||||
<!-- ziel -->
|
||||
Entfernt Dokument, Versionen und Dateien endgültig
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf löschen
|
||||
- Ein laufender Neuaufbau verhindert das Löschen
|
||||
- Versionsdateien werden mitgelöscht
|
||||
- Ein Auftrag hält den Vorgang fest
|
||||
- Der Index ändert sich beim nächsten Neuaufbau
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Dokument verschwindet
|
||||
77
daten/MtoRagSystem/.planung/evalfall.md
Normal file
@@ -0,0 +1,77 @@
|
||||
<!-- titel -->
|
||||
Evalfall
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Beschreibt einen prüfbaren Fall für die Antwortgüte
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Neun Falltypen stehen im Adminbereich
|
||||
- Ein zehnter Typ läuft nur im Terminal
|
||||
- Eine Fallkennung ist projektweit eindeutig
|
||||
- Pflichtfelder sind Kennung, Typ und Frage
|
||||
- Fälle liegen als Zeilendatei je Typ und Bereich
|
||||
- Schreiben erfolgt mit ausschließender Sperre
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Bereich wählen
|
||||
<!-- ziel -->
|
||||
Schaltet zwischen Systembasis und Fachbereich
|
||||
<!-- regeln -->
|
||||
- Der Bereich prägt jede weitere Handlung
|
||||
- Fachbereiche liegen in eigenen Ordnern
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf einen Bereichsreiter
|
||||
- Fälle des Bereichs sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evalfall anlegen
|
||||
<!-- regeln -->
|
||||
- Doppelte Kennung wird abgewiesen
|
||||
- Erwartung muss ein Objekt sein
|
||||
- Verlauf muss eine Liste sein
|
||||
- Ein Fehler verhindert jede Änderung
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf neuer Test
|
||||
- Formular ausfüllen
|
||||
- Absenden
|
||||
- Fall in der Datei
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evalfall geführt anlegen
|
||||
<!-- ziel -->
|
||||
Legt einen Fall über einen Assistenten an
|
||||
<!-- regeln -->
|
||||
- Eigener Entwurf mit eigener Fehlerprüfung
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf Assistent
|
||||
- Schritte ausfüllen
|
||||
- Fall in der Datei
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evalfall ableiten
|
||||
<!-- ziel -->
|
||||
Übernimmt einen gescheiterten Lauf als Fall
|
||||
<!-- regeln -->
|
||||
- Kennung und Frage werden vorbelegt
|
||||
<!-- testen -->
|
||||
- Lauf mit Fehlschlag öffnen
|
||||
- LMB auf Fall übernehmen
|
||||
- Formular vorbefüllt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evalfall löschen
|
||||
<!-- regeln -->
|
||||
- Eine defekte Zeile verhindert die Änderung
|
||||
- Unbekannte Kennung meldet einen Fehler
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Seite neuer Test öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Fall verschwindet
|
||||
100
daten/MtoRagSystem/.planung/evallauf.md
Normal file
@@ -0,0 +1,100 @@
|
||||
<!-- titel -->
|
||||
Evallauf
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Prüft die Antwortpipeline gegen gespeicherte Fälle
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein gescheiterter Fall setzt den Gesamtstand
|
||||
- Eine leere Auswahl gilt nicht als Fehlschlag
|
||||
- Berichte entstehen unteilbar
|
||||
- Evals messen Fälle, nicht jede mögliche Frage
|
||||
- Fünf Falltypen rufen das Modell
|
||||
- Vier Falltypen laufen ohne Modell
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evallauf starten
|
||||
<!-- ziel -->
|
||||
Führt Fälle aus dem Adminbereich aus
|
||||
<!-- regeln -->
|
||||
- Der Lauf braucht die Wissensrolle
|
||||
- Der Bericht wird zusätzlich archiviert
|
||||
- Der Lauf blockiert die Anfrage bis zum Ende
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- Auswahl treffen
|
||||
- Lauf starten
|
||||
- Ergebnis je Fall sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Einzelfall erneut testen
|
||||
<!-- ziel -->
|
||||
Wiederholt genau einen gescheiterten Fall
|
||||
<!-- regeln -->
|
||||
- Nur der gewählte Fall läuft
|
||||
<!-- testen -->
|
||||
- Lauf mit Fehlschlag öffnen
|
||||
- LMB auf erneut testen
|
||||
- Ergebnis des Falls sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Läufe vergleichen
|
||||
<!-- ziel -->
|
||||
Stellt zwei Berichte als Unterschied gegenüber
|
||||
<!-- regeln -->
|
||||
- Der Vergleich nennt behoben, neu und entfernt
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- Vergleichsbasis wählen
|
||||
- Unterschied sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evallauf im Terminal ausführen
|
||||
<!-- regeln -->
|
||||
- Die Auswahl folgt Typ und Bereich
|
||||
- Ein Abbruch nach dem ersten Fehler ist wählbar
|
||||
- Ein Lauf ohne Schreiben ist wählbar
|
||||
- Fälle lassen sich nur auflisten
|
||||
<!-- testen -->
|
||||
- Kommando mit Typ aufrufen
|
||||
- Ergebnis je Fall sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evallauf parallelisieren
|
||||
<!-- ziel -->
|
||||
Verteilt Fälle auf mehrere Kindprozesse
|
||||
<!-- regeln -->
|
||||
- Zwischen einem und 32 Prozessen
|
||||
- Vorgabe sind zwei Prozesse
|
||||
- Ein Zeitlimit je Prozess ist wählbar
|
||||
- Das Ergebnis ist ein Sammelbericht
|
||||
<!-- testen -->
|
||||
- Kommando mit Prozesszahl aufrufen
|
||||
- Sammelbericht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Berichte aufräumen
|
||||
<!-- regeln -->
|
||||
- Nur erzeugte Dateinamen fallen weg
|
||||
- Aufräumen behält 20 Läufe je Bereich
|
||||
- Die Liste zeigt zehn Läufe
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf Aufräumen
|
||||
- Berichtszahl sinkt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Berichte löschen
|
||||
<!-- ziel -->
|
||||
Entfernt alle Läufe eines Bereichs
|
||||
<!-- regeln -->
|
||||
- Der aktuelle Lauf fällt mit weg
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf alle löschen
|
||||
- Bestätigen
|
||||
- Berichtsliste leer
|
||||
138
daten/MtoRagSystem/.planung/fremdinhalt.md
Normal file
@@ -0,0 +1,138 @@
|
||||
<!-- titel -->
|
||||
Fremdinhalt
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Prüft externe Inhalte vor jeder Nutzung
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Geprüft wird der ausgewählte Inhalt
|
||||
- Ein Lesen führt kein Werkzeug aus
|
||||
- Ein Lesen ändert die Antwortpipeline nicht
|
||||
- Vorschauen sind gekürzt und bereinigt
|
||||
- Externe Inhalte heben ihren Rang nicht selbst
|
||||
- Der Bereich braucht die höchste Rolle
|
||||
- Keine Übernahme ins Standardwissen erfolgt automatisch
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt live prüfen
|
||||
<!-- ziel -->
|
||||
Liest den ausgewählten Inhalt einmalig online
|
||||
<!-- regeln -->
|
||||
- Nur der gewählte Inhalt wird gelesen
|
||||
- Ohne Zutun wird nichts gespeichert
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Inhalt prüfen
|
||||
- Bestätigen
|
||||
- Vorschau mit Abrufzahl
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt bereitstellen
|
||||
<!-- ziel -->
|
||||
Merkt einen gelesenen Inhalt als Kandidat vor
|
||||
<!-- regeln -->
|
||||
- Chat und Antwortnutzung bleiben aus
|
||||
- Der Kandidat startet ohne Freigabe
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Inhalt live prüfen
|
||||
- LMB auf bereitstellen
|
||||
- Bestätigen
|
||||
- Kandidat in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt auswählen
|
||||
<!-- ziel -->
|
||||
Ordnet einen Inhalt einem Raum zur Prüfung zu
|
||||
<!-- regeln -->
|
||||
- Zwei Arten: eigener Raum und Ergänzung
|
||||
- Die Auswahl gilt schon als geprüft
|
||||
- Die Auswahl schaltet den Chat nicht ein
|
||||
- Standardwissen wird dadurch nicht ergänzt
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- LMB auf Inhalt auswählen
|
||||
- Bestätigen
|
||||
- Inhalt im Freigabebereich
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt entscheiden
|
||||
<!-- ziel -->
|
||||
Gibt einen geprüften Inhalt frei oder stellt zurück
|
||||
<!-- regeln -->
|
||||
- Fünf Wege bis zum Zurücksetzen
|
||||
- Eine unbekannte Entscheidung wird abgewiesen
|
||||
- Eine Freigabe schaltet den Chat nicht ein
|
||||
- Die Notiz endet bei 1000 Zeichen
|
||||
<!-- testen -->
|
||||
- Freigabebereich öffnen
|
||||
- LMB auf Inhalt ansehen
|
||||
- Entscheidung wählen
|
||||
- Zustandsmarke wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt im Chat einschalten
|
||||
<!-- ziel -->
|
||||
Fügt einen freigegebenen Inhalt dem Raum zu
|
||||
<!-- regeln -->
|
||||
- Nur geprüfte Inhalte eines eigenen Raums
|
||||
- Nicht vorbereitete Inhalte werden abgewiesen
|
||||
- Suche und Belege bleiben unberührt
|
||||
- Es entsteht kein gespeichertes Wissen
|
||||
<!-- testen -->
|
||||
- Freigabebereich öffnen
|
||||
- LMB auf im Chat einschalten
|
||||
- Inhalt als aktiv markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Kandidaten filtern
|
||||
<!-- ziel -->
|
||||
Grenzt vorbereitete Inhalte nach Zustand ein
|
||||
<!-- regeln -->
|
||||
- Filter nach Zustand, Anbindung, Art und Zeit
|
||||
- Das Filtern ruft nichts extern ab
|
||||
<!-- testen -->
|
||||
- Vorbereitete Inhalte öffnen
|
||||
- Filter setzen
|
||||
- Trefferliste eingegrenzt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Kandidat entfernen
|
||||
<!-- ziel -->
|
||||
Löscht einen vorbereiteten Inhalt endgültig
|
||||
<!-- regeln -->
|
||||
- Die Vorschau fällt mit weg
|
||||
<!-- testen -->
|
||||
- Vorbereitete Inhalte öffnen
|
||||
- LMB auf Entfernen
|
||||
- Kandidat verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Kandidaten ausgeben
|
||||
<!-- ziel -->
|
||||
Lädt vorbereitete Inhalte als Datei herunter
|
||||
<!-- regeln -->
|
||||
- Zwei Formate: Markdown und JSONL
|
||||
- Der Export gibt die gefilterte Menge aus
|
||||
- Der Export wirkt nicht als Freigabe
|
||||
<!-- testen -->
|
||||
- Vorbereitete Inhalte öffnen
|
||||
- Format wählen
|
||||
- Herunterladen
|
||||
- Datei im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Ressource lesen
|
||||
<!-- ziel -->
|
||||
Liest eine freigegebene Ressource im Terminal
|
||||
<!-- regeln -->
|
||||
- Nur erlaubte Server und Adressen
|
||||
- Der Inhalt wird bereinigt
|
||||
- Ausgegeben werden nur Metadaten und Prüfsumme
|
||||
- Eine Kürzung wird gekennzeichnet
|
||||
<!-- testen -->
|
||||
- Kommando mit Adresse aufrufen
|
||||
- Metadaten und Prüfsumme sichtbar
|
||||
64
daten/MtoRagSystem/.planung/indexprofil.md
Normal file
@@ -0,0 +1,64 @@
|
||||
<!-- titel -->
|
||||
Indexprofil
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Legt Struktur für Chunking und Einbettung fest
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein Profil ist unveränderlich
|
||||
- Genau ein Profil ist aktiv
|
||||
- Einsehen braucht die Wissensrolle
|
||||
- Ändern braucht die höchste Rolle
|
||||
- Die Version zählt beim Anlegen hoch
|
||||
- Ein neues Profil entsteht inaktiv
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profile prüfen
|
||||
<!-- ziel -->
|
||||
Gleicht das aktive Profil gegen den Index ab
|
||||
<!-- regeln -->
|
||||
- Der Vergleich läuft gegen die Indexmetadaten
|
||||
- Eine abweichende Zeile setzt den Gesamtstand
|
||||
- Fehlende Metadaten gelten als Strukturabweichung
|
||||
- Die Ansicht startet keinen Neuaufbau
|
||||
<!-- testen -->
|
||||
- Menüeintrag Indexprofile wählen
|
||||
- Abweichungen je Zeile sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil anlegen
|
||||
<!-- regeln -->
|
||||
- Chunkgröße von 50 bis 1000 in Schritten von 25
|
||||
- Überlappung von 25 bis 200 in Schritten von 25
|
||||
- Das Einbettungsmodell ist Pflicht
|
||||
- Fehlende Pflichtwerte nennen das Feld
|
||||
- Nur die höchste Rolle darf anlegen
|
||||
<!-- testen -->
|
||||
- Indexprofile öffnen
|
||||
- Werte eintragen
|
||||
- Profil erstellen
|
||||
- Inaktives Profil sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil aktivieren
|
||||
<!-- regeln -->
|
||||
- Das bisherige Profil wird deaktiviert
|
||||
- Die Aktivierung startet keinen Neuaufbau
|
||||
<!-- testen -->
|
||||
- Indexprofile öffnen
|
||||
- LMB auf Aktivieren
|
||||
- Bestätigen
|
||||
- Profil als aktiv markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil löschen
|
||||
<!-- regeln -->
|
||||
- Der Löschweg erscheint nur bei inaktiven Profilen
|
||||
<!-- testen -->
|
||||
- Indexprofile öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Profil verschwindet
|
||||
46
daten/MtoRagSystem/.planung/konfiguration.md
Normal file
@@ -0,0 +1,46 @@
|
||||
<!-- titel -->
|
||||
Konfiguration
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Prüft die wirksamen Einstellungen vor dem Betrieb
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Fachsemantik gehört in die Konfiguration
|
||||
- Harte Sonderpfade im Antwortkern sind verboten
|
||||
- Geänderter Kataloginhalt wirkt ohne Codeänderung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Konfiguration validieren
|
||||
<!-- regeln -->
|
||||
- Fehler und Warnungen erscheinen getrennt
|
||||
- Warnungen ändern den Ausgang nicht
|
||||
- Regressionswächter melden nur Warnungen
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Fehler- und Warnliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Konfiguration ausgeben
|
||||
<!-- ziel -->
|
||||
Zeigt die aufgelöste Einstellung zur Diagnose
|
||||
<!-- regeln -->
|
||||
- Die Ausgabe ist nicht bereinigt
|
||||
- Pfade und Adressen stehen darin
|
||||
- Nur der Shopschlüssel bleibt verborgen
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Vollständige Ausgabe sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Quellen auditieren
|
||||
<!-- ziel -->
|
||||
Prüft Herkunft, Muster und Fachneutralität
|
||||
<!-- regeln -->
|
||||
- Reine Quelltextanalyse ohne Laufzeitwirkung
|
||||
- Ein Fehlerstand beendet den Lauf
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Kennzahlen und Funde sichtbar
|
||||
68
daten/MtoRagSystem/.planung/modellprofil.md
Normal file
@@ -0,0 +1,68 @@
|
||||
<!-- titel -->
|
||||
Modellprofil
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Stellt Modell und Suchparameter der Antwort ein
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Höchstens ein Profil ist systemweit aktiv
|
||||
- Ohne aktives Profil greifen die Vorgabewerte
|
||||
- Die Version zählt je Modellname hoch
|
||||
- Ein neues Profil entsteht inaktiv
|
||||
- Ein aktives Profil lässt sich nicht löschen
|
||||
- Nur fehlende Felder erben die Vorgabewerte
|
||||
- Wertebereiche greifen erst beim Aktivieren
|
||||
- Suchwerte werden still auf 1 bis 200 begrenzt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profile auflisten
|
||||
<!-- regeln -->
|
||||
- Das aktive Profil steht oben
|
||||
- Die Anzeige startet keine Erzeugung
|
||||
<!-- testen -->
|
||||
- Menüeintrag Modellsetup wählen
|
||||
- Profilliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil erstellen
|
||||
<!-- regeln -->
|
||||
- Der Modellname ist Pflicht
|
||||
- Nur die höchste Rolle darf anlegen
|
||||
<!-- testen -->
|
||||
- Profilliste öffnen
|
||||
- Werte eintragen
|
||||
- Absenden
|
||||
- Inaktives Profil sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil aktivieren
|
||||
<!-- testen -->
|
||||
- Profilliste öffnen
|
||||
- LMB auf Aktivieren
|
||||
- Bestätigen
|
||||
- Profil als aktiv markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil löschen
|
||||
<!-- testen -->
|
||||
- Profilliste öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Profil verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Suche testen
|
||||
<!-- ziel -->
|
||||
Prüft das Trefferverhalten eines Profils
|
||||
<!-- regeln -->
|
||||
- Leere Frage liefert kein Ergebnis
|
||||
- Der Test ändert das Profil nicht
|
||||
- Der Test aktiviert das Profil nicht
|
||||
<!-- testen -->
|
||||
- Profilliste öffnen
|
||||
- LMB auf Testen
|
||||
- Frage eintragen
|
||||
- Trefferliste sichtbar
|
||||
43
daten/MtoRagSystem/.planung/protokoll.md
Normal file
@@ -0,0 +1,43 @@
|
||||
<!-- titel -->
|
||||
Protokoll
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Zeigt Betriebsmeldungen der Dienste
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf lesen
|
||||
- Die Anzeige ist rein lesend
|
||||
- Kein Löschen ist vorgesehen
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Protokolle auflisten
|
||||
<!-- regeln -->
|
||||
- Nur Dateien nach festem Namensmuster
|
||||
- Neueste Änderung steht oben
|
||||
<!-- testen -->
|
||||
- Menüeintrag Protokolle wählen
|
||||
- Dateiliste mit Größe sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Protokoll anzeigen
|
||||
<!-- regeln -->
|
||||
- Höchstens 1000 Zeilen
|
||||
- Gelesen wird vom Dateiende
|
||||
- Eine fehlende Datei meldet einen Fehler
|
||||
<!-- testen -->
|
||||
- Protokollliste öffnen
|
||||
- LMB auf Anzeigen
|
||||
- Letzte Zeilen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Vektorprotokoll anzeigen
|
||||
<!-- regeln -->
|
||||
- Feste Quelle im Protokollverzeichnis
|
||||
- Höchstens 500 Zeilen
|
||||
- Eine fehlende Datei meldet einen Hinweis
|
||||
<!-- testen -->
|
||||
- Menüeintrag Vektorprotokoll wählen
|
||||
- Letzte Zeilen sichtbar
|
||||
99
daten/MtoRagSystem/.planung/rueckmeldung.md
Normal file
@@ -0,0 +1,99 @@
|
||||
<!-- titel -->
|
||||
Rückmeldung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Sammelt Nutzerkritik für die Verbesserung
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Eine Rückmeldung hängt an einer Antwort
|
||||
- Die Adminsicht braucht die Wissensrolle
|
||||
- Ein Löschen ist endgültig
|
||||
- Der Export enthält Frage und Antwort im Klartext
|
||||
- Der Export folgt den gesetzten Filtern
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldungen filtern
|
||||
<!-- ziel -->
|
||||
Grenzt Fälle nach zehn Merkmalen ein
|
||||
<!-- regeln -->
|
||||
- Filter nach Bewertung und Bearbeitungsstand
|
||||
- Filter nach Einordnung und Fehlerverdacht
|
||||
- Filter nach Vorrang und Referenzwert
|
||||
- Seitengröße wählbar mit 25, 50 oder 100
|
||||
<!-- testen -->
|
||||
- Menüeintrag Chat-Feedback wählen
|
||||
- Filter setzen
|
||||
- Trefferliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldung ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt einen Fall mit Frage und Antwort
|
||||
<!-- testen -->
|
||||
- Rückmeldungen filtern
|
||||
- LMB auf einen Fall
|
||||
- Frage und Antwort sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldung erledigen
|
||||
<!-- regeln -->
|
||||
- Eine Notiz ist möglich
|
||||
<!-- testen -->
|
||||
- Rückmeldung ansehen
|
||||
- LMB auf erledigt
|
||||
- Zustand wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldung wieder öffnen
|
||||
<!-- testen -->
|
||||
- Erledigte Rückmeldung ansehen
|
||||
- LMB auf wieder öffnen
|
||||
- Zustand wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldungen gesammelt erledigen
|
||||
<!-- ziel -->
|
||||
Setzt den Stand für die ganze Auswahl
|
||||
<!-- regeln -->
|
||||
- Auswahl über Kästchen oder Filter
|
||||
- Höchstens 5000 Fälle je Aktion
|
||||
<!-- testen -->
|
||||
- Rückmeldungen filtern
|
||||
- Auswahl treffen
|
||||
- LMB auf Auswahl erledigen
|
||||
- Zustände wechseln
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldung löschen
|
||||
<!-- testen -->
|
||||
- Rückmeldung ansehen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Eintrag verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldungen ausgeben
|
||||
<!-- regeln -->
|
||||
- Zwei Formate: Markdown und JSONL
|
||||
- Der Export ist nicht bereinigt
|
||||
- Vorgefertigte Auszüge je Vorrang
|
||||
<!-- testen -->
|
||||
- Rückmeldungen filtern
|
||||
- Format wählen
|
||||
- Datei im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldungen einordnen
|
||||
<!-- ziel -->
|
||||
Bestimmt Typ, Risiko und Vorrang im Terminal
|
||||
<!-- regeln -->
|
||||
- Ohne Erzwingen nur ungeordnete Einträge
|
||||
- Höchstens 5000 Einträge je Lauf
|
||||
- Vorgabe sind 500 Einträge
|
||||
- Zwischenstände werden gespeichert
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Zähler je Risiko sichtbar
|
||||
76
daten/MtoRagSystem/.planung/selbsttest.md
Normal file
@@ -0,0 +1,76 @@
|
||||
<!-- titel -->
|
||||
Selbsttest
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Sichert Grenzen des Systems gegen Rückschritte
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- 23 Selbsttests decken die Regressionsfläche
|
||||
- Jeder Test hat sein eigenes Kommando
|
||||
- Es gibt kein Sammelkommando
|
||||
- Jeder Test liefert Fallliste und Ausgang
|
||||
- Jeder Test kennt eine maschinenlesbare Ausgabe
|
||||
- 15 Tests prüfen nur den Quelltext
|
||||
- Sechs Tests prüfen gemischt
|
||||
- Zwei Tests prüfen nur Verhalten
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Einzeltest ausführen
|
||||
<!-- ziel -->
|
||||
Prüft eine benannte Grenze des Systems
|
||||
<!-- regeln -->
|
||||
- Kein Modell, kein Netz, keine Antwort
|
||||
- Keine Datenbank und kein Import
|
||||
- Ein gescheiterter Fall beendet den Lauf
|
||||
<!-- testen -->
|
||||
- Kommandonamen aus der Übersicht holen
|
||||
- Kommando aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Ingestgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Sichert Markdown, Chunks und Batchgrenzen ab
|
||||
<!-- regeln -->
|
||||
- Zwölf Kommandos decken diesen Bereich
|
||||
- Ein Test räumt sein Verzeichnis selbst auf
|
||||
<!-- testen -->
|
||||
- Kommando aus der Ingestgruppe aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindungsgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Sichert Fremddaten und Werkzeuggrenzen ab
|
||||
<!-- regeln -->
|
||||
- Drei Kommandos decken diesen Bereich
|
||||
- Verbotene Zeichenketten gelten als Fall
|
||||
<!-- testen -->
|
||||
- Kommando aus der Anbindungsgruppe aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Architekturgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Sichert Flussgrenzen und Produktregeln ab
|
||||
<!-- regeln -->
|
||||
- Fünf Kommandos decken diesen Bereich
|
||||
- Ein Test hängt an einer Freigabeversion
|
||||
<!-- testen -->
|
||||
- Kommando aus der Architekturgruppe aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Antwortgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Sichert Anker, Prüfung und Raumauswahl ab
|
||||
<!-- regeln -->
|
||||
- Drei Kommandos decken diesen Bereich
|
||||
- Keine Chatantwort und kein Shopzugriff
|
||||
- Unbelegte Begriffe bleiben unrepariert
|
||||
<!-- testen -->
|
||||
- Kommando aus der Antwortgruppe aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
75
daten/MtoRagSystem/.planung/shoptreffer.md
Normal file
@@ -0,0 +1,75 @@
|
||||
<!-- titel -->
|
||||
Shoptreffer
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Liefert Preis und Verfügbarkeit aus dem Shop
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Der Preis stammt allein aus dem Shopdatensatz
|
||||
- Ohne Shoppreis erscheint kein Preis
|
||||
- Ein fehlender Preis wird nicht zu null
|
||||
- Kostenlos gilt nur mit Quellenbeleg
|
||||
- Verfügbarkeit stammt allein aus dem Shopfeld
|
||||
- Die Produktadresse stammt aus dem Shoppfad
|
||||
- Reine Wissensantworten tragen keine Shopadressen
|
||||
- Ein Shoptreffer belegt keine technische Eignung
|
||||
- Zubehör wird nicht als Hauptgerät ausgegeben
|
||||
- Bündelangaben bleiben unzerlegt
|
||||
- Gefilterte Treffer sind keine fehlenden Treffer
|
||||
- Kein Treffer bedeutet nicht: gibt es nicht
|
||||
- Ein Shopausfall wird gemeldet
|
||||
- Bei automatischer Basis startet sie nur bei Kaufbezug
|
||||
- Die Basis Shop erzwingt die Suche
|
||||
- Die gesendete Suchanfrage wird offengelegt
|
||||
- Bilder stammen aus dem Bildfeld desselben Datensatzes
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Shopsuche auslösen
|
||||
<!-- ziel -->
|
||||
Sucht aus einer Wissensantwort passende Produkte
|
||||
<!-- regeln -->
|
||||
- Angebot entfällt bei gleicher Suche
|
||||
- Angebot entfällt bei ablehnender Antwort
|
||||
- Eine erweiterte Suche wird ausgewiesen
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf Shopsuche
|
||||
- Trefferliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Preis nachfragen
|
||||
<!-- ziel -->
|
||||
Ruft Handelsdaten zum genannten Produkt ab
|
||||
<!-- regeln -->
|
||||
- Angebot entfällt bei genanntem Preis
|
||||
- Die Folgeantwort bleibt am Produkt
|
||||
<!-- testen -->
|
||||
- Frage nach einem Produkt stellen
|
||||
- LMB auf Preis anzeigen
|
||||
- Preis und Artikelnummer sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Treffer filtern
|
||||
<!-- ziel -->
|
||||
Grenzt die Liste auf Zubehör oder Geräte ein
|
||||
<!-- regeln -->
|
||||
- Angebot erscheint nur bei Wirkung
|
||||
- Mehrdeutige Rollen gelten nicht als Gerät
|
||||
<!-- testen -->
|
||||
- Shopsuche auslösen
|
||||
- LMB auf eine Rolle
|
||||
- Liste eingegrenzt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Shopsuche diagnostizieren
|
||||
<!-- ziel -->
|
||||
Prüft eine Suchanfrage samt Reparatur im Terminal
|
||||
<!-- regeln -->
|
||||
- Der Zugriff läuft live gegen den Shop
|
||||
- Die Reparatursuche bevorzugt den angefragten Code
|
||||
<!-- testen -->
|
||||
- Kommando mit Suchtext aufrufen
|
||||
- Suchanfrage und Treffer sichtbar
|
||||
90
daten/MtoRagSystem/.planung/sicherung.md
Normal file
@@ -0,0 +1,90 @@
|
||||
<!-- titel -->
|
||||
Sicherung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Sichert Anwendung und Datenbank nachvollziehbar
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Geheimnisse werden nie mitkopiert
|
||||
- Fremdbibliotheken und Zwischenspeicher bleiben draußen
|
||||
- Ein Datenbankabzug entsteht auf Anforderung oder Vorgabe
|
||||
- Eine Sperrdatei verhindert parallele Läufe
|
||||
- Sieben Stände bleiben rollierend erhalten
|
||||
- Symlinks werden übersprungen
|
||||
- Ein Verzeichnis nennt Umfang und Kennung
|
||||
- Eine gelungene Sicherung beweist keinen Restore
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherung testen
|
||||
<!-- ziel -->
|
||||
Prüft den geplanten Umfang ohne Schreibvorgang
|
||||
<!-- regeln -->
|
||||
- Keine Sicherungsdatei entsteht
|
||||
- Keine alte Sicherung fällt weg
|
||||
- Fehlende Pflichtquellen erscheinen als Warnung
|
||||
- Fehlende Zusatzquellen zählen getrennt
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Sicherung testen
|
||||
- Umfang und Warnungen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherung starten
|
||||
<!-- regeln -->
|
||||
- Ein Datenbankabzug braucht Schalter oder Vorgabe
|
||||
- Das Verzeichnis nennt keinen Zugang
|
||||
- Geräumte Sicherungen werden benannt
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Sicherung starten
|
||||
- Bestätigen
|
||||
- Sicherung in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherung herunterladen
|
||||
<!-- ziel -->
|
||||
Holt ein Archiv für den Restore-Test
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf herunterladen
|
||||
- Nur gültige lokale Kennungen
|
||||
- Der Abruf startet keine Sicherung
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Herunterladen
|
||||
- Archiv im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Restore prüfen
|
||||
<!-- ziel -->
|
||||
Bewertet eine Sicherung als Wiederherstellungsgrundlage
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf prüfen
|
||||
- Es läuft keine Wiederherstellung
|
||||
- Kein Datenbankimport erfolgt
|
||||
- Gelesen werden Verzeichnis und Bestandteile
|
||||
- Das Ergebnis liefert einen Plan
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Restore prüfen
|
||||
- Prüfpunkte und Plan sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherung im Terminal erstellen
|
||||
<!-- regeln -->
|
||||
- Ein Trockenlauf schreibt keine Datei
|
||||
- Die Aufbewahrung ist wählbar
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Kennung und Umfang sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Restore im Terminal prüfen
|
||||
<!-- regeln -->
|
||||
- Kein Netz, kein Modell, kein Chat
|
||||
<!-- testen -->
|
||||
- Kommando mit Kennung aufrufen
|
||||
- Prüfpunkte und Plan sichtbar
|
||||
83
daten/MtoRagSystem/.planung/sitzung.md
Normal file
@@ -0,0 +1,83 @@
|
||||
<!-- titel -->
|
||||
Sitzung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Hält Zugang und Verlauf einer Unterhaltung
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Chat und Adminbereich teilen eine Anmeldung
|
||||
- Ein Abmelden beendet beide Bereiche
|
||||
- Der Verlauf hängt an einem Browserkennzeichen
|
||||
- Ein Abmelden löscht dieses Kennzeichen nicht
|
||||
- Deaktivierte Konten werden abgewiesen
|
||||
- Der Verlauf löst nur Bezüge auf
|
||||
- Der Verlauf belegt keine Fachwerte
|
||||
- Ein Hinweis nennt Fehlerrisiko und Datennutzung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Am Chat anmelden
|
||||
<!-- regeln -->
|
||||
- E-Mail und Passwort sind Pflicht
|
||||
- Ohne Chatrolle erscheint eine Verbotsseite
|
||||
- Falscher Zugang behält die E-Mail
|
||||
- Angemeldete landen sofort im Chat
|
||||
<!-- testen -->
|
||||
- Anmeldeseite aufrufen
|
||||
- E-Mail und Passwort eintragen
|
||||
- Bestätigen
|
||||
- Chat mit Verlauf sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Vom Chat abmelden
|
||||
<!-- regeln -->
|
||||
- Gemerkte Einstellungen bleiben erhalten
|
||||
<!-- testen -->
|
||||
- LMB auf Abmelden
|
||||
- Anmeldeseite sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Am Adminbereich anmelden
|
||||
<!-- regeln -->
|
||||
- Ohne Adminrolle erscheint eine Verbotsseite
|
||||
- Berechtigte landen auf der Systemübersicht
|
||||
- Der letzte Benutzername ist vorbelegt
|
||||
<!-- testen -->
|
||||
- Adminanmeldung aufrufen
|
||||
- E-Mail und Passwort eintragen
|
||||
- Bestätigen
|
||||
- Systemübersicht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Vom Adminbereich abmelden
|
||||
<!-- testen -->
|
||||
- LMB auf Abmelden
|
||||
- Anmeldeseite sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Verlauf löschen
|
||||
<!-- ziel -->
|
||||
Entfernt Gespräch, Produktbezüge und Uploads
|
||||
<!-- regeln -->
|
||||
- Während des Empfangs gesperrt
|
||||
- Löscht alle temporären Uploads mit
|
||||
- Keine Rückfrage, keine Wiederherstellung
|
||||
- Danach fehlen alle Bezugsanker
|
||||
<!-- testen -->
|
||||
- LMB auf Verlauf löschen
|
||||
- Verlauf leer
|
||||
- Uploadliste leer
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Hilfe öffnen
|
||||
<!-- ziel -->
|
||||
Zeigt das Bedienhandbuch im Chat
|
||||
<!-- regeln -->
|
||||
- Nur bei vorhandener Handbuchdatei
|
||||
- Höchstens 512 KB werden gelesen
|
||||
- Die Hilfe ändert keine Antwortlogik
|
||||
<!-- testen -->
|
||||
- LMB auf Hilfe
|
||||
- Handbuch im Fenster sichtbar
|
||||
46
daten/MtoRagSystem/.planung/systemprompt.md
Normal file
@@ -0,0 +1,46 @@
|
||||
<!-- titel -->
|
||||
Systemprompt
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Steuert die Grundanweisung an das Modell
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Genau eine Version ist aktiv
|
||||
- Die Version zählt fortlaufend hoch
|
||||
- Eine neue Version überschreibt keine alte
|
||||
- Nur die höchste Rolle darf ändern
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Version speichern
|
||||
<!-- regeln -->
|
||||
- Leerer Inhalt wird abgewiesen
|
||||
- Die neue Version wird sofort aktiv
|
||||
- Die bisherige Version wird abgeschaltet
|
||||
<!-- testen -->
|
||||
- Menüeintrag Systemprompt wählen
|
||||
- Text eintragen
|
||||
- Speichern
|
||||
- Neue aktive Version oben
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Version aktivieren
|
||||
<!-- ziel -->
|
||||
Schaltet auf eine frühere Version zurück
|
||||
<!-- testen -->
|
||||
- Systemprompt öffnen
|
||||
- LMB auf Aktivieren
|
||||
- Bestätigen
|
||||
- Kennzeichnung wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Version löschen
|
||||
<!-- regeln -->
|
||||
- Eine aktive Version bleibt geschützt
|
||||
<!-- testen -->
|
||||
- Systemprompt öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Version verschwindet
|
||||
92
daten/MtoRagSystem/.planung/tag.md
Normal file
@@ -0,0 +1,92 @@
|
||||
<!-- titel -->
|
||||
Tag
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Lenkt die Suche über gepflegte Signale
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Drei Typen: allgemein, Katalogobjekt, Vertriebssignal
|
||||
- Unbekannter Typ fällt auf allgemein
|
||||
- Ein Slug ist eindeutig
|
||||
- Jede Änderung stößt einen Neuaufbau an
|
||||
- Ein laufender Neuaufbau verhindert einen zweiten
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Tag anlegen
|
||||
<!-- regeln -->
|
||||
- Slug und Bezeichnung sind Pflicht
|
||||
- Der Slug wird kleingeschrieben
|
||||
- Leerzeichen werden zu Bindestrichen
|
||||
- Ein doppelter Slug wird abgewiesen
|
||||
<!-- testen -->
|
||||
- Tagliste öffnen
|
||||
- Bezeichnung und Slug eintragen
|
||||
- Anlegen
|
||||
- Tag in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Tag löschen
|
||||
<!-- regeln -->
|
||||
- Alle Zuweisungen fallen mit weg
|
||||
<!-- testen -->
|
||||
- Tagliste öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Tag verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Dokumente zuweisen
|
||||
<!-- ziel -->
|
||||
Ordnet einem Tag mehrere Dokumente zu
|
||||
<!-- regeln -->
|
||||
- Nur aktive Dokumente stehen zur Wahl
|
||||
- Doppelte Kennungen werden entfernt
|
||||
- Nur Unterschiede werden geschrieben
|
||||
<!-- testen -->
|
||||
- Tagliste öffnen
|
||||
- LMB auf Zuweisen
|
||||
- Dokumente ankreuzen
|
||||
- Speichern
|
||||
- Zähler angepasst
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Dokument-Tags bearbeiten
|
||||
<!-- ziel -->
|
||||
Setzt die Tags eines einzelnen Dokuments
|
||||
<!-- regeln -->
|
||||
- Tags erscheinen nach Typ sortiert
|
||||
- Nicht angekreuzte Tags fallen weg
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- LMB auf Tags
|
||||
- Tags ankreuzen
|
||||
- Speichern
|
||||
- Neuaufbau angestoßen
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Neuaufbau verfolgen
|
||||
<!-- ziel -->
|
||||
Zeigt den Fortschritt des Tag-Neuaufbaus laufend
|
||||
<!-- regeln -->
|
||||
- Der Stand wird zweisekündlich abgefragt
|
||||
- Ein Lebenszeichen kommt zehnsekündlich
|
||||
- Vier Zustände: wartend, laufend, fertig, gescheitert
|
||||
- Das Zusehen stößt keinen Neuaufbau an
|
||||
<!-- testen -->
|
||||
- Tagliste öffnen
|
||||
- Statuszeile beobachten
|
||||
- Zustand wechselt bis fertig
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Tagindex neu aufbauen
|
||||
<!-- ziel -->
|
||||
Baut Tagexport und Tagvektoren im Terminal neu
|
||||
<!-- regeln -->
|
||||
- Entweder Auftragskennung oder Neuanlage
|
||||
- Eine Sperrdatei verhindert Parallelläufe
|
||||
<!-- testen -->
|
||||
- Kommando mit Neuanlage aufrufen
|
||||
- Kennzahlen sichtbar
|
||||
68
daten/MtoRagSystem/.planung/upload.md
Normal file
@@ -0,0 +1,68 @@
|
||||
<!-- titel -->
|
||||
Upload
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Stellt eine Datei als Quelle der Sitzung bereit
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Erlaubt sind PDF, Markdown und Text
|
||||
- Höchstens drei Dateien je Sitzung
|
||||
- Höchstens 10 MB je Datei
|
||||
- Ein Upload verfällt nach 60 Minuten
|
||||
- Uploads ändern die Wissensbasis nie
|
||||
- Ein Upload beginnt nachrangig
|
||||
- Ein Upload lässt sich auf vorrangig stellen
|
||||
- Der ausgewertete Text endet bei 60000 Zeichen
|
||||
- Der Client prüft, der Server prüft erneut
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Datei hochladen
|
||||
<!-- regeln -->
|
||||
- Eine leere Datei weist erst der Server ab
|
||||
- Übergroße Datei wird abgewiesen
|
||||
- Bei erreichtem Maximum ist der Zugang gesperrt
|
||||
- Ein Upload beginnt nachrangig
|
||||
<!-- testen -->
|
||||
- LMB auf Hinzufügen
|
||||
- Datei wählen
|
||||
- Datei mit Größe sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Nutzung wählen
|
||||
<!-- ziel -->
|
||||
Legt fest, ob der Upload allein zählt
|
||||
<!-- regeln -->
|
||||
- Abfrage erscheint nach dem Hochladen
|
||||
- Als eigener Raum zählt nur der Upload
|
||||
- Als Ergänzung bleibt Standardwissen führend
|
||||
- Ohne Freigabe bleibt Standardwissen wirksam
|
||||
<!-- testen -->
|
||||
- Datei hochladen
|
||||
- Eine Nutzungsart wählen
|
||||
- Wissensraum passt sich an
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Upload priorisieren
|
||||
<!-- ziel -->
|
||||
Hebt den Upload gegenüber dem Wissen an
|
||||
<!-- regeln -->
|
||||
- Zwei Modi: nachrangig und vorrangig
|
||||
- Als eigener Raum entfällt der Schalter
|
||||
- Ein Widerspruch bleibt sichtbar ausgewiesen
|
||||
<!-- testen -->
|
||||
- Datei hochladen
|
||||
- LMB auf den Rangvermerk
|
||||
- Vermerk zeigt vorrangig
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Upload entfernen
|
||||
<!-- regeln -->
|
||||
- Wirkt nur auf eigene Uploads
|
||||
- Ohne Upload fällt der Raum zurück
|
||||
<!-- testen -->
|
||||
- Datei hochladen
|
||||
- LMB auf Entfernen
|
||||
- Datei verschwindet
|
||||
135
daten/MtoRagSystem/.planung/version.md
Normal file
@@ -0,0 +1,135 @@
|
||||
<!-- titel -->
|
||||
Version
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Hält einen unveränderlichen Stand eines Dokuments
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Eine Version wird nie überschrieben
|
||||
- Jede Version trägt eine Prüfsumme
|
||||
- Eine neue Version entsteht inaktiv
|
||||
- Nur die aktive Version speist den Index
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Version hochladen
|
||||
<!-- ziel -->
|
||||
Legt einen Nachfolgestand als neue Version ab
|
||||
<!-- regeln -->
|
||||
- Die Datei ist Pflicht
|
||||
- Die Nummer zählt vom höchsten Stand hoch
|
||||
- Die aktive Version bleibt unverändert
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf neue Version
|
||||
- Datei wählen
|
||||
- Hochladen
|
||||
- Inaktive Version sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Originaltext ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt die Textbasis vor der Chunk-Erzeugung
|
||||
<!-- regeln -->
|
||||
- Die Anzeige ändert die Datei nicht
|
||||
- Jede Seite liefert 40000 Zeichen
|
||||
- Eine angeforderte Seitengröße endet bei 80000
|
||||
- Weitere Seiten laden beim Blättern nach
|
||||
- Nicht lesbare Formate melden einen Fehler
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf Original ansehen
|
||||
- Text im Fenster sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Version ableiten
|
||||
<!-- ziel -->
|
||||
Speichert korrigierten Text als neue Version
|
||||
<!-- regeln -->
|
||||
- Die Arbeitskopie endet bei 180000 Zeichen
|
||||
- Leerer Inhalt wird abgewiesen
|
||||
- Der Dateiname nennt die Quellversion
|
||||
- Quelle und aktive Version bleiben unberührt
|
||||
- Die neue Version ist inaktiv
|
||||
<!-- testen -->
|
||||
- Originaltext ansehen
|
||||
- Text anpassen
|
||||
- Als neue Version speichern
|
||||
- Inaktive Version sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Wissenskarte erzeugen
|
||||
<!-- ziel -->
|
||||
Erstellt eine strukturierte Markdown-Fassung der Version
|
||||
<!-- regeln -->
|
||||
- Die Quelle wird segmentiert verarbeitet
|
||||
- Ein unvollständiger Plan bricht ab
|
||||
- Der Zusammenbau erfolgt durch das System
|
||||
- Der Nachweis nennt Modell und Segmentzahl
|
||||
- Kein Index wird geschrieben
|
||||
- Doppelklicks bleiben während des Laufs gesperrt
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf Wissenskarte erzeugen
|
||||
- Bestätigen
|
||||
- Neue inaktive Version sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Version aktivieren
|
||||
<!-- ziel -->
|
||||
Wählt eine Version als künftige Antwortbasis
|
||||
<!-- regeln -->
|
||||
- Genau eine Version bleibt aktiv
|
||||
- Die Version wird zum Neuaufbau vorgemerkt
|
||||
- Kein Auftrag und kein Neuaufbau startet
|
||||
- Bis dahin gilt der letzte stabile Index
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf Version aktivieren
|
||||
- Bestätigen
|
||||
- Warnung zum Neuaufbau sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Version vormerken
|
||||
<!-- ziel -->
|
||||
Markiert die aktive Version für den Neuaufbau
|
||||
<!-- regeln -->
|
||||
- Nur die aktive Version lässt sich vormerken
|
||||
- Es startet kein Einzellauf
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf vormerken
|
||||
- Bestätigen
|
||||
- Version als vorgemerkt markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Chunks lesen
|
||||
<!-- ziel -->
|
||||
Zeigt die Chunks einer Version aus dem Index
|
||||
<!-- regeln -->
|
||||
- Die Anzeige ändert keine Antwortlogik
|
||||
- Höchstens 300 Chunks je Version
|
||||
- Je Chunk höchstens 1400 Zeichen
|
||||
- Je Chunk höchstens 30 Fakten
|
||||
- Ohne Indexeinträge erscheint eine Warnung
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf Chunks lesen
|
||||
- Chunkliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Chunkgüte vergleichen
|
||||
<!-- ziel -->
|
||||
Stellt Original und Wissenskarte gegenüber
|
||||
<!-- regeln -->
|
||||
- Die Prüfung läuft nur im Speicher
|
||||
- Kein Index wird geschrieben
|
||||
- Kein Modell wird aufgerufen
|
||||
- Ein fehlendes Gegenstück meldet einen Hinweis
|
||||
- Der Vergleich nennt Chunks, Tabellen und Fakten
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf Güte vergleichen
|
||||
- Vergleich sichtbar
|
||||
72
daten/MtoRagSystem/.planung/vision.md
Normal file
@@ -0,0 +1,72 @@
|
||||
<!-- titel -->
|
||||
Vision
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
vision
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Antworten sollen nicht nur plausibel klingen, sondern nachprüfbar sein.
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Beleggeführt antworten
|
||||
<!-- ziel -->
|
||||
Jede Aussage bekommt einen nachvollziehbaren Belegzustand
|
||||
- Was nicht in den Quellen steht, wird nicht behauptet
|
||||
- Belegzustand und Abdeckung sind ablesbar
|
||||
- Einzelne Aussagen werden gegen die Belege geprüft
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Grenzen zeigen
|
||||
<!-- ziel -->
|
||||
Fehlendes, Schwaches und Widersprüchliches bleibt sichtbar
|
||||
- Fehlende Quellen werden benannt, nicht ersetzt
|
||||
- Quellenkonflikte werden gezeigt statt zusammengeführt
|
||||
- Transparente Unsicherheit schlägt sichere Falschaussage
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Quellen trennen
|
||||
<!-- ziel -->
|
||||
Fachwissen, Handelsdaten und Uploads bleiben unterscheidbar
|
||||
- Ein Shoppreis belegt keine technische Eignung
|
||||
- Wissensräume trennen die Bestände sichtbar
|
||||
- Ein Upload bleibt temporär und nachrangig
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Wissen pflegen
|
||||
<!-- ziel -->
|
||||
Dokumente werden antwortfähig, nicht nur abgelegt
|
||||
- Versionen bleiben einzeln nachvollziehbar
|
||||
- Struktur, Chunks und Fakten sind einsehbar
|
||||
- Ein Neuaufbau ist eine bewusste Entscheidung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Fremddaten kontrollieren
|
||||
<!-- ziel -->
|
||||
Externe Quellen wirken nur nach bewusster Freigabe
|
||||
- Nichts wird automatisch zu Standardwissen
|
||||
- Nur lesende Werkzeuge, nie Schreibaktionen
|
||||
- Jede Freigabe ist eine eigene Entscheidung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Fachfrei bleiben
|
||||
<!-- ziel -->
|
||||
Fachsemantik gehört in Konfiguration, nicht in den Kern
|
||||
- Harte Sonderpfade im Antwortkern sind verboten
|
||||
- Ein Fachpaket ist pflegbar ohne Codeänderung
|
||||
- Diagnosen verändern die Antwortgüte nicht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Betrieb nachweisen
|
||||
<!-- ziel -->
|
||||
Der Betreiber kann belegen, dass das System trägt
|
||||
- Prüfungen, Sicherungen und Berichte sind abrufbar
|
||||
- Berichte enthalten keine Geheimnisse
|
||||
- Ein Restore-Nachweis bleibt Aufgabe des Betreibers
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Grenzen des Systems anerkennen
|
||||
<!-- ziel -->
|
||||
Das System ersetzt keine Prüfung durch Menschen
|
||||
- Es gibt keine Rechteverwaltung im Wissen
|
||||
- Kein Ersatz für Audit, Rechtsrat oder Abkommen
|
||||
- Evals messen Fälle, nicht universelle Wahrheit
|
||||
56
daten/MtoRagSystem/.planung/werkzeug.md
Normal file
@@ -0,0 +1,56 @@
|
||||
<!-- titel -->
|
||||
Werkzeug
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Erlaubt ein lesendes Werkzeug im Anbindungsraum
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Nur eindeutig lesende Werkzeuge sind erlaubt
|
||||
- Werkzeuge mit Schreibrisiko bleiben gesperrt
|
||||
- Eine Freigabe gilt nur für ihren Raum
|
||||
- Das Modell schlägt vor, das System führt aus
|
||||
- Ein freigegebenes Werkzeug läuft ohne Rückfrage
|
||||
- Höchstens ein Werkzeug je Antwort
|
||||
- Jede Nutzung erhält einen Nachweis
|
||||
- Ein Werkzeugfehler wird sichtbar gemeldet
|
||||
- Standardwissen und Shop bleiben ausgeschlossen
|
||||
- Der Bereich braucht die höchste Rolle
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Werkzeug freigeben
|
||||
<!-- regeln -->
|
||||
- Nicht eindeutig lesende Werkzeuge bleiben gesperrt
|
||||
- Der Grund für eine Sperre steht dabei
|
||||
- Die Freigabe führt kein Werkzeug aus
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- Abschnitt Werkzeuge aufklappen
|
||||
- LMB auf freigeben
|
||||
- Werkzeug als freigegeben markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Werkzeugfreigabe zurücknehmen
|
||||
<!-- regeln -->
|
||||
- Die Rücknahme wirkt sofort
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- Abschnitt Werkzeuge aufklappen
|
||||
- LMB auf Freigabe entfernen
|
||||
- Werkzeug wieder gesperrt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Werkzeugergebnis auswählen
|
||||
<!-- ziel -->
|
||||
Ordnet ein gespeichertes Ergebnis einem Raum zu
|
||||
<!-- regeln -->
|
||||
- Kein Werkzeug läuft dabei
|
||||
- Ergebnisse bleiben gespeicherte Prüfinformationen
|
||||
- Ergebnisse sind nicht live lesbar
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- Abschnitt Ergebnisse aufklappen
|
||||
- LMB auf auswählen
|
||||
- Ergebnis im Freigabebereich
|
||||
90
daten/MtoRagSystem/.planung/wissensindex.md
Normal file
@@ -0,0 +1,90 @@
|
||||
<!-- titel -->
|
||||
Wissensindex
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Hält die durchsuchbare Fassung des Wissens
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Treffer unter der Mindestgüte fallen weg
|
||||
- Jeder Treffer trägt eine Chunkkennung
|
||||
- Dokument und Abschnitt kommen mit, sofern vorhanden
|
||||
- Eine nicht erreichbare Suche liefert keine Treffer
|
||||
- Ein veralteter Index wird gemeldet
|
||||
- Ein unvollständiger Aufbau bricht ab
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Systemstand ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt Chunkzahl und Gesundheit der Dienste
|
||||
<!-- regeln -->
|
||||
- Die Anzeige schreibt nichts
|
||||
- Die harte Chunkgrenze liegt bei 25000
|
||||
<!-- testen -->
|
||||
- Menüeintrag Systemübersicht wählen
|
||||
- Chunkzahl und Gesundheit sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Chunkindex einsehen
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf einsehen
|
||||
- Vorgabe 50, höchstens 200 Einträge je Seite
|
||||
- Die Anzeige startet keinen Neuaufbau
|
||||
<!-- testen -->
|
||||
- Menüeintrag Wissensbasis wählen
|
||||
- Metadaten und Einträge sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Zwischenspeicher leeren
|
||||
<!-- ziel -->
|
||||
Verwirft kurzlebige Zwischenstände nach Wartung
|
||||
<!-- regeln -->
|
||||
- Der Dienst kennt keine Antwortlogik
|
||||
- Ein nicht erreichbarer Vektordienst ergibt eine Warnung
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Systemübersicht öffnen
|
||||
- LMB auf Zwischenspeicher leeren
|
||||
- Bestätigen
|
||||
- Ergebnismeldung sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Gesundheit prüfen
|
||||
<!-- ziel -->
|
||||
Prüft Vektor- und Tagindex im Terminal
|
||||
<!-- regeln -->
|
||||
- Gesund ist jeder Zustand mit Vorsilbe OK
|
||||
- Es entsteht kein Schreibzugriff
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Prüfbericht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Vektordienst steuern
|
||||
<!-- ziel -->
|
||||
Startet, stoppt oder lädt den Vektordienst neu
|
||||
<!-- regeln -->
|
||||
- Die Steuerung läuft über das Kontrollskript
|
||||
- Das Zeitlimit beträgt 600 Sekunden
|
||||
<!-- testen -->
|
||||
- Kommando mit Aktion aufrufen
|
||||
- Ausgabe des Skripts sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Wissen zurücksetzen
|
||||
<!-- ziel -->
|
||||
Löscht Dokumente, Versionen, Tags und Indexdateien
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf ausführen
|
||||
- Die Funktion ist standardmäßig gesperrt
|
||||
- Der Bestätigungstext muss wörtlich stimmen
|
||||
- Zuvor entsteht eine Sicherung
|
||||
- Ein Fehlschlag der Sicherung bricht ab
|
||||
<!-- testen -->
|
||||
- Systemübersicht öffnen
|
||||
- Bestätigungstext eintippen
|
||||
- Absenden
|
||||
- Bestätigen
|
||||
- Sicherungspfad sichtbar
|
||||
97
daten/MtoRagSystem/.planung/wissensraum.md
Normal file
@@ -0,0 +1,97 @@
|
||||
<!-- titel -->
|
||||
Wissensraum
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Bestimmt, welcher Bestand eine Antwort trägt
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Standardwissen ist immer verfügbar
|
||||
- Standardwissen lässt sich nicht abschalten
|
||||
- Ein Uploadraum antwortet nur aus dem Upload
|
||||
- Ein Uploadraum kennt keinen stillen Rückfall
|
||||
- Ein Anbindungsraum liest nur Freigegebenes
|
||||
- Ein Anbindungsraum mischt kein Standardwissen
|
||||
- Ein unbekannter Raum fällt auf Standardwissen
|
||||
- Freigegebene Inhalte und Werkzeugergebnisse sind nachrangig
|
||||
- Beide bleiben vom Rangvorteil ausgenommen
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Wissensraum wählen
|
||||
<!-- ziel -->
|
||||
Legt die Antwortgrundlage der Unterhaltung fest
|
||||
<!-- regeln -->
|
||||
- Der Uploadraum braucht einen gültigen Upload
|
||||
- Gesperrte Räume sind nicht wählbar
|
||||
- Während des Empfangs gesperrt
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Wissensraum wählen
|
||||
- Raum in der Zusammenfassung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Räume überblicken
|
||||
<!-- ziel -->
|
||||
Zeigt, welche Räume arbeiten und angeboten werden
|
||||
<!-- regeln -->
|
||||
- Der Zugang braucht die höchste Rolle
|
||||
- Anbindungen sind erst nach Freigabe wirksam
|
||||
<!-- testen -->
|
||||
- Menüeintrag Wissensräume wählen
|
||||
- Räume mit Zählern sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Chatauswahl umschalten
|
||||
<!-- ziel -->
|
||||
Gibt einen Raum für die Chatauswahl frei
|
||||
<!-- regeln -->
|
||||
- Standardwissen bleibt gesperrt
|
||||
- Ausschalten löscht keine Freigaben
|
||||
- Wiedereinschalten braucht keine neue Freigabe
|
||||
- Nicht vorgesehene Räume werden abgewiesen
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- LMB auf Einschalten
|
||||
- Raum als aktiv markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Freigegebenen Inhalt vorschauen
|
||||
<!-- ziel -->
|
||||
Liest einen freigegebenen Inhalt vor der Entscheidung
|
||||
<!-- regeln -->
|
||||
- Der Dialog liest nur auf Klick
|
||||
- Kein Standardwissen und kein Werkzeug
|
||||
- Es wird nichts gespeichert
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- Freigabebereich öffnen
|
||||
- LMB auf live lesen
|
||||
- Textvorschau sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Herkunft ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt, welche Inhalte welchem Raum gehören
|
||||
<!-- regeln -->
|
||||
- Reine Anzeige ohne Freigabe
|
||||
- Kein externer Abruf entsteht
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- Abschnitt Herkunft aufklappen
|
||||
- Zuordnungen je Raum sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Raumgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Führt sechs Selbsttests zu den Raumgrenzen aus
|
||||
<!-- regeln -->
|
||||
- Es entsteht keine Chatantwort
|
||||
- Kein Werkzeug wird ausgeführt
|
||||
- Kein Inhalt wird live gelesen
|
||||
- Netz und Speicher werden je Test ausgewiesen
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- LMB auf Prüfungen ausführen
|
||||
- Sammelergebnis sichtbar
|
||||
2735
daten/MtoRagSystem/.pruefung.json
Normal file
1
daten/MtoRagSystem/.verzeichnis
Normal file
@@ -0,0 +1 @@
|
||||
/home/arbeit/arbeit/MtoRagSystem
|
||||
157
daten/MtoRagSystem/anbindung.md
Normal file
@@ -0,0 +1,157 @@
|
||||
<!-- titel -->
|
||||
Anbindung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Bindet einen externen Server kontrolliert an
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein Token wird nie gespeichert, nur sein Name
|
||||
- Eine Anbindung startet eingeschaltet, ohne Chatfreigabe
|
||||
- Eine Anbindung wirkt erst nach Freigabe
|
||||
- Ein Import führt nie ein Werkzeug aus
|
||||
- Ein Import liest keine Inhalte
|
||||
- Anweisungen fremder Inhalte werden entfernt
|
||||
- Ein Transport über Standardeingabe ist gesperrt
|
||||
- Nur verschlüsselte Verbindungen sind erlaubt
|
||||
- Interne Netze sind gesperrt
|
||||
- Weiterleitungen werden nicht verfolgt
|
||||
- Protokolle enthalten nur Metadaten
|
||||
- Der Bereich braucht die höchste Rolle
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung anlegen
|
||||
<!-- regeln -->
|
||||
- Speichern folgt einer bestandenen Prüfung
|
||||
- Ein Speichern ändert keine Antwort
|
||||
- Ein Formulartoken ist Pflicht
|
||||
<!-- testen -->
|
||||
- Menüeintrag MCP Quellen wählen
|
||||
- Reiter Anbindung anlegen wählen
|
||||
- Formular ausfüllen
|
||||
- Anbindung speichern
|
||||
- Anbindung in der Übersicht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung prüfen
|
||||
<!-- ziel -->
|
||||
Testet die Angaben gegen Erlaubnisliste und Regeln
|
||||
<!-- regeln -->
|
||||
- Ohne Onlinetest entstehen keine Abrufe
|
||||
- Das Ergebnis nennt den Grund
|
||||
- Die Prüfung speichert nicht
|
||||
<!-- testen -->
|
||||
- Formular ausfüllen
|
||||
- LMB auf Anbindung prüfen
|
||||
- Prüfergebnis mit Begründung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung bearbeiten
|
||||
<!-- regeln -->
|
||||
- Änderungen wirken erst nach dem Speichern
|
||||
- Werkzeugdaten bleiben erhalten
|
||||
- Zugewiesene Inhalte bleiben am Kurznamen gebunden
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Bearbeiten
|
||||
- Formular vorbefüllt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung umschalten
|
||||
<!-- ziel -->
|
||||
Legt eine Anbindung vorübergehend still
|
||||
<!-- regeln -->
|
||||
- Ausgewählte Inhalte bleiben gespeichert
|
||||
- Eine stillgelegte Anbindung wirkt nicht
|
||||
- Wiedereinschalten braucht keine neue Freigabe
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Deaktivieren
|
||||
- Zustandsmarke wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung entfernen
|
||||
<!-- regeln -->
|
||||
- Der Raum wird zuvor abgeschaltet
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Entfernen
|
||||
- Bestätigen
|
||||
- Anbindung verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Ressource übernehmen
|
||||
<!-- ziel -->
|
||||
Schreibt eine gefundene Ressource in die Anbindung
|
||||
<!-- regeln -->
|
||||
- Nur erkannte Ressourcen sind übernehmbar
|
||||
- Die Übernahme schaltet den Chat nicht ein
|
||||
<!-- testen -->
|
||||
- Serverinhalte aktualisieren
|
||||
- LMB auf Ressource übernehmen
|
||||
- Ressource in der Anbindung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Serverinhalte aktualisieren
|
||||
<!-- ziel -->
|
||||
Erkennt Ressourcen, Werkzeuge und Vorlagen als Metadaten
|
||||
<!-- regeln -->
|
||||
- Kein Werkzeug wird ausgeführt
|
||||
- Vorlagen werden erkannt, nie ausgeführt
|
||||
- Ressourcen werden nicht gelesen
|
||||
- Gefundene Werkzeuge sind zunächst gesperrt
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Inhalte aktualisieren
|
||||
- Gefundene Inhalte sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindung online prüfen
|
||||
<!-- ziel -->
|
||||
Prüft eine gespeicherte Anbindung im Terminal
|
||||
<!-- regeln -->
|
||||
- Geprüft werden Freigabe und ein Inhalt
|
||||
- Ohne prüfbaren Inhalt bricht der Lauf ab
|
||||
- Ein fehlendes Geheimnis blockt vorher
|
||||
- Anfragen werden bereinigt protokolliert
|
||||
<!-- testen -->
|
||||
- Kommando mit Servernamen aufrufen
|
||||
- Prüfbericht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Schutzregeln ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt Grenzen und Systemprüfung der Anbindungen
|
||||
<!-- regeln -->
|
||||
- Die Anzeige ruft nichts extern ab
|
||||
- Freie Werkzeugnutzung ist gesperrt
|
||||
<!-- testen -->
|
||||
- Menüeintrag Quellen wählen
|
||||
- Reiter Sicherheit wählen
|
||||
- Grenzen und Prüfstand sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Freigaben prüfen
|
||||
<!-- ziel -->
|
||||
Prüft die Serverliste der Grundeinstellung
|
||||
<!-- regeln -->
|
||||
- Kein Transport wird geöffnet
|
||||
- Das Ergebnis nennt Server, Fehler und Warnungen
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Prüfstand je Regel sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Brücke trocken testen
|
||||
<!-- ziel -->
|
||||
Prüft Bereinigung und Belegbrücke ohne Serverkontakt
|
||||
<!-- regeln -->
|
||||
- Nur lokale Nutzlasten werden geprüft
|
||||
- Kein Transport, keine Chatwirkung
|
||||
- Fremde Anweisungsmarker fallen weg
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Bereinigte Nutzlast sichtbar
|
||||
115
daten/MtoRagSystem/antwort.md
Normal file
@@ -0,0 +1,115 @@
|
||||
<!-- titel -->
|
||||
Antwort
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Beantwortet eine Frage aus geprüften Quellen
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Nur Aussagen aus den Quellen
|
||||
- Fehlende Werte werden nicht erfunden
|
||||
- Keine Schätzung ersetzt einen fehlenden Wert
|
||||
- Fakten und Ableitungen bleiben getrennt
|
||||
- Ableitungen sind als solche markiert
|
||||
- Eignung gilt als belegpflichtige Aussage
|
||||
- Negativaussagen brauchen einen Quellenbeleg
|
||||
- Werbesprache ist untersagt
|
||||
- Sprache der Frage gilt für die Antwort
|
||||
- Interne Belegkennungen bleiben auf Nachfrage beschränkt
|
||||
- Interne Denktexte erreichen niemanden
|
||||
- Die genutzte Datenbasis steht an der Antwort
|
||||
- Trefferzahl aus Wissen und Shop liegt bei
|
||||
- Die Antwortdauer wird ausgewiesen
|
||||
- Ein Vertrauensabzeichen steht an der Antwort
|
||||
- Wiederholungsschleifen werden sichtbar abgeschnitten
|
||||
- Transparente Unsicherheit schlägt sichere Falschaussage
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Frage stellen
|
||||
<!-- ziel -->
|
||||
Sendet eine Frage und empfängt die Antwort laufend
|
||||
<!-- regeln -->
|
||||
- Leere Frage wird abgewiesen
|
||||
- Höchstens 10000 Zeichen
|
||||
- Warnung ab 7500 Zeichen
|
||||
- Erneutes Senden bleibt bis zum Ende gesperrt
|
||||
- Entwurf überlebt einen Neuladen
|
||||
- Unterbrochener Empfang wird fortgesetzt
|
||||
- Ein Lauf verfällt nach 900 Sekunden
|
||||
- Ein stehender Lauf wird beendet
|
||||
<!-- testen -->
|
||||
- Text eingeben
|
||||
- Enter drücken
|
||||
- Frage im Verlauf
|
||||
- Antwort läuft ein
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Antwort abbrechen
|
||||
<!-- ziel -->
|
||||
Beendet eine laufende Antwort vorzeitig
|
||||
<!-- regeln -->
|
||||
- Nur während des Empfangs möglich
|
||||
- Der Serverlauf arbeitet weiter
|
||||
- Der Vermerk gilt nur in der laufenden Ansicht
|
||||
- Nach dem Neuladen steht die volle Antwort
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf Abbrechen
|
||||
- Abbruchvermerk im Verlauf
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Frage erneut senden
|
||||
<!-- ziel -->
|
||||
Wiederholt die Frage mit anderer Einstellung
|
||||
<!-- regeln -->
|
||||
- Angeboten sind nur ungenutzte Varianten
|
||||
- Der Klick setzt die Einstellung passend
|
||||
- Während des Empfangs gesperrt
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf eine Variante
|
||||
- Frage erneut im Verlauf
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Antwortmodus wählen
|
||||
<!-- ziel -->
|
||||
Wählt zwischen gründlicher und schneller Antwort
|
||||
<!-- regeln -->
|
||||
- Zwei Werte: Standard und schnell
|
||||
- Ungültiger Wert fällt auf Standard
|
||||
- Der schnelle Modus nutzt ein anderes Modell
|
||||
- Der schnelle Modus antwortet ungenauer
|
||||
- Die Wahl gilt für die ganze Unterhaltung
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Antwortmodus wählen
|
||||
- Modus an der nächsten Antwort
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Datenbasis wählen
|
||||
<!-- ziel -->
|
||||
Legt fest, ob Wissen oder Shopdaten zählen
|
||||
<!-- regeln -->
|
||||
- Vier Werte: automatisch, Wissen, Shop, beides
|
||||
- Unbekannter Wert fällt auf automatisch
|
||||
- Nur Wissen löst keine Shopsuche aus
|
||||
- Die genutzte Basis steht in der Antwort
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Datenbasis wählen
|
||||
- Basis in der Zusammenfassung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Folgeaktion auslösen
|
||||
<!-- ziel -->
|
||||
Sendet eine vorgeschlagene Folgefrage sofort
|
||||
<!-- regeln -->
|
||||
- Der Fragetext kommt vom Server
|
||||
- Angebot entfällt bei ablehnender Antwort
|
||||
- Während des Empfangs passiert nichts
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf eine Folgeaktion
|
||||
- Folgefrage im Verlauf
|
||||
85
daten/MtoRagSystem/auftrag.md
Normal file
@@ -0,0 +1,85 @@
|
||||
<!-- titel -->
|
||||
Auftrag
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Führt Indexierung und Neuaufbau nachvollziehbar aus
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Jeder Lauf hinterlässt einen Auftrag
|
||||
- Der Auftrag nennt Typ, Zustand, Zeiten und Person
|
||||
- Fünf Zustände bis zum Abbruch
|
||||
- Nur der Neuaufbau schreibt eine Protokolldatei
|
||||
- Nur ein Indexlauf läuft gleichzeitig
|
||||
- Ein Strukturwechsel erzwingt einen sichtbaren Neuaufbau
|
||||
- Ein unvollständiger Aufbau bricht ab
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Aufträge einsehen
|
||||
<!-- ziel -->
|
||||
Zeigt den Verlauf aller Indexläufe
|
||||
<!-- regeln -->
|
||||
- Neueste Aufträge stehen oben
|
||||
- Der Fehlertext endet in der Liste bei 120 Zeichen
|
||||
<!-- testen -->
|
||||
- Menüeintrag Aufträge wählen
|
||||
- Auftragsliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Auftrag verfolgen
|
||||
<!-- ziel -->
|
||||
Beobachtet einen einzelnen Lauf bis zum Ende
|
||||
<!-- regeln -->
|
||||
- Die Kennung muss dem Kennungsformat folgen
|
||||
- Der Stand wird zweisekündlich nachgeladen
|
||||
- Geliefert werden Typ, Zustand, Zeiten und Fehler
|
||||
- Das Nachladen endet mit dem Auftrag
|
||||
<!-- testen -->
|
||||
- Auftragsliste öffnen
|
||||
- LMB auf eine Kennung
|
||||
- Zustandsmarke wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Index neu aufbauen
|
||||
<!-- ziel -->
|
||||
Überführt vorgemerkte Änderungen in den Index
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf starten
|
||||
- Der Auftrag beginnt wartend
|
||||
- Die Arbeit läuft im Hintergrund
|
||||
- Ein Fehlstart markiert den Auftrag als gescheitert
|
||||
- Nach Erfolg wird der Zwischenspeicher geleert
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- LMB auf Index neu aufbauen
|
||||
- Bestätigen
|
||||
- Auftragsseite sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Auftrag ausführen
|
||||
<!-- ziel -->
|
||||
Startet einen vorhandenen Auftrag im Terminal
|
||||
<!-- regeln -->
|
||||
- Unbekannte Kennung wird abgewiesen
|
||||
- Abgeschlossene Aufträge laufen nicht erneut
|
||||
- Ein Trockenlauf vermeidet schwere Schritte
|
||||
<!-- testen -->
|
||||
- Kommando mit Kennung aufrufen
|
||||
- Zustandszeile sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Index hart neu aufbauen
|
||||
<!-- ziel -->
|
||||
Baut Chunks, Vektoren und Tags vollständig neu
|
||||
<!-- regeln -->
|
||||
- Ohne Erzwingen bricht der Lauf ab
|
||||
- Vier Schritte laufen in fester Reihenfolge
|
||||
- Einzelne Schritte lassen sich überspringen
|
||||
- Ein gescheiterter Schritt beendet den Lauf
|
||||
- Ein Trockenlauf schreibt keine Indexdatei
|
||||
<!-- testen -->
|
||||
- Kommando mit Erzwingen aufrufen
|
||||
- Vier Schritte sichtbar
|
||||
- Gesundheitsstand am Ende
|
||||
118
daten/MtoRagSystem/batch.md
Normal file
@@ -0,0 +1,118 @@
|
||||
<!-- titel -->
|
||||
Batch
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Importiert viele Dokumente in einem Lauf
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Höchstens 250 Dateien je Upload
|
||||
- Erlaubt sind PDF, Text, Markdown und Word
|
||||
- Geschützte PDF gelten als nicht verarbeitbar
|
||||
- Doppelte Prüfsummen werden übersprungen
|
||||
- Höchstens ein Neuaufbau je Lauf
|
||||
- Ohne Indexwirkung entfällt der Neuaufbau
|
||||
- Der Eingang wird nach dem Lauf geräumt
|
||||
- Je gelungener Lauf entsteht ein Bericht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Batch hochladen
|
||||
<!-- ziel -->
|
||||
Lädt viele Dateien gesammelt und verarbeitet sie
|
||||
<!-- regeln -->
|
||||
- Ohne Datei bricht der Lauf ab
|
||||
- Titel entstehen aus Dateinamen oder Manifest
|
||||
- Schwache Titel werden markiert
|
||||
- Wissenskarten entstehen nur auf Wunsch
|
||||
- Aktivierung ohne Wissenskarte wird verworfen
|
||||
<!-- testen -->
|
||||
- Menüeintrag Batch wählen
|
||||
- Dateien wählen
|
||||
- Batch starten
|
||||
- Ergebniszahlen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Batch vorab prüfen
|
||||
<!-- ziel -->
|
||||
Prüft einen Eingang ohne jede Schreibwirkung
|
||||
<!-- regeln -->
|
||||
- Kein Dokument wird importiert
|
||||
- Kein Modell wird aufgerufen
|
||||
- Dateityp, Prüfsumme und Dubletten werden geprüft
|
||||
- Zusatzschalter erzeugen eine Warnung
|
||||
<!-- testen -->
|
||||
- Kommando im Trockenlauf aufrufen
|
||||
- Bericht mit Dateiliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Batch importieren
|
||||
<!-- ziel -->
|
||||
Importiert einen Eingang im Terminal
|
||||
<!-- regeln -->
|
||||
- Der Import ist über Prüfsummen wiederholbar
|
||||
- Ohne eindeutigen Benutzer bricht der Lauf ab
|
||||
- Der Kommandolauf hat keine Dateigrenze
|
||||
- Erfolgreiche Quellen verlassen den Eingang
|
||||
- Fehler und Übersprungenes landen getrennt
|
||||
- Abgeleitete Versionen bleiben ohne Schalter inaktiv
|
||||
<!-- testen -->
|
||||
- Kommando mit Eingang aufrufen
|
||||
- Bericht als Datei geschrieben
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Berichte auflisten
|
||||
<!-- regeln -->
|
||||
- Höchstens 100 Berichte, neueste oben
|
||||
- Defekte Berichte werden übersprungen
|
||||
<!-- testen -->
|
||||
- Menüeintrag Batch wählen
|
||||
- Berichtsliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Bericht ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt einen Lauf je Datei und Schritt
|
||||
<!-- regeln -->
|
||||
- Die Kennung darf keine Sonderzeichen tragen
|
||||
- Ein unbekannter Bericht meldet einen Fehler
|
||||
- Die Ansicht startet keine Verarbeitung
|
||||
<!-- testen -->
|
||||
- Berichtsliste öffnen
|
||||
- LMB auf Anzeigen
|
||||
- Schritte und Dateien sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Bericht herunterladen
|
||||
<!-- regeln -->
|
||||
- Zwei Formate: JSON und Markdown
|
||||
- Eine fehlende Datei meldet einen Fehler
|
||||
<!-- testen -->
|
||||
- Berichtsliste öffnen
|
||||
- LMB auf ein Format
|
||||
- Datei im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Bericht löschen
|
||||
<!-- regeln -->
|
||||
- Beide Formate fallen zusammen weg
|
||||
- Dokumente und Index bleiben unberührt
|
||||
<!-- testen -->
|
||||
- Berichtsliste öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Bericht verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Eingang bereinigen
|
||||
<!-- ziel -->
|
||||
Räumt leere Ordner und falsche Ablagen auf
|
||||
<!-- regeln -->
|
||||
- Die Bereinigung wirkt nur im Importverzeichnis
|
||||
- Namenskollisionen bekommen einen Zähler
|
||||
- Kein Einfluss auf Suche oder Antwort
|
||||
<!-- testen -->
|
||||
- Menüeintrag Batch wählen
|
||||
- LMB auf Eingang bereinigen
|
||||
- Zahl geräumter Ordner sichtbar
|
||||
71
daten/MtoRagSystem/beleg.md
Normal file
@@ -0,0 +1,71 @@
|
||||
<!-- titel -->
|
||||
Beleg
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Weist nach, worauf eine Aussage sich stützt
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Belegquellen sind Wissen, Shop und URL-Inhalte
|
||||
- Frühere Antworten belegen keine Fachwerte
|
||||
- Jede Antwort erhält genau einen Belegzustand
|
||||
- Direkt belegt gilt nur bei einem tragenden Beleg
|
||||
- Verstreute Anforderungen ergeben schwach belegt
|
||||
- Fehlende Pflichtangabe ergibt nicht vollständig belegt
|
||||
- Ohne Quelle gilt nicht geprüft
|
||||
- Jeder Beleg trägt eine Stärke
|
||||
- Fehlende Pflichtmerkmale werden einzeln benannt
|
||||
- Direkte Dokumentquellen stehen unter der Antwort
|
||||
- Höchstens vier Quellentitel erscheinen
|
||||
- Eine genutzte Uploaddatei bleibt in der Quellenliste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Belegdetails aufklappen
|
||||
<!-- ziel -->
|
||||
Zeigt Prüfsignale hinter der Vertrauenslage
|
||||
<!-- regeln -->
|
||||
- Ohne echte Signale erscheint keine Belegkarte
|
||||
- Konflikte werden gesondert benannt
|
||||
- Die Anzeige gilt für alle sichtbaren Antworten
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf technische Details
|
||||
- Claims und Belege sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Zusatzinfos umschalten
|
||||
<!-- ziel -->
|
||||
Blendet Quellen und Folgeaktionen ein
|
||||
<!-- regeln -->
|
||||
- Nur genutzte Quellen werden gelistet
|
||||
- Die Einstellung überlebt einen Neuladen
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Zusatzinfos umschalten
|
||||
- Quellenblock verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Statusprotokoll einschalten
|
||||
<!-- ziel -->
|
||||
Macht Prüf- und Quellenschritte sichtbar
|
||||
<!-- regeln -->
|
||||
- Der Bereich öffnet sich beim Einschalten
|
||||
- Statusinfos stehen neben dem Verlauf
|
||||
- Fehlermeldungen bleiben immer sichtbar
|
||||
- Prompts und Geheimnisse erscheinen nie
|
||||
<!-- testen -->
|
||||
- Chat-Einstellungen öffnen
|
||||
- Statusprotokoll einschalten
|
||||
- Seitenbereich mit Zeitleiste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Statusprotokoll schließen
|
||||
<!-- regeln -->
|
||||
- Schließen schaltet die Einstellung aus
|
||||
- Der Zustand überlebt einen Neuladen
|
||||
<!-- testen -->
|
||||
- Statusprotokoll einschalten
|
||||
- LMB auf Schließen im Bereich
|
||||
- Bereich verschwindet
|
||||
82
daten/MtoRagSystem/benutzer.md
Normal file
@@ -0,0 +1,82 @@
|
||||
<!-- titel -->
|
||||
Benutzer
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Regelt Zugang und Rollen der Menschen
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein Passwort wird nur verschlüsselt gespeichert
|
||||
- Eine E-Mail ist eindeutig
|
||||
- Ein deaktiviertes Konto wird abgewiesen
|
||||
- Niemand deaktiviert sich selbst
|
||||
- Der letzte oberste Verwalter bleibt geschützt
|
||||
- Die Verwaltung braucht die höchste Rolle
|
||||
- Ein Konto lässt sich nicht löschen
|
||||
- Deaktivierung beendet die laufende Sitzung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer filtern
|
||||
<!-- regeln -->
|
||||
- Filter nach Text, Zustand und Rolle
|
||||
- Die Suche trifft Namen, E-Mail und Abteilung
|
||||
- Ein ungültiger Wert fällt auf alle
|
||||
- Die Gesamtzahlen bleiben ungefiltert
|
||||
<!-- testen -->
|
||||
- Menüeintrag Benutzer wählen
|
||||
- Filter setzen
|
||||
- LMB auf Filtern
|
||||
- Trefferzahl sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer erstellen
|
||||
<!-- regeln -->
|
||||
- Das Passwort braucht acht Zeichen
|
||||
- Die Wiederholung muss übereinstimmen
|
||||
- Mindestens eine Rolle ist Pflicht
|
||||
- Unbekannte Rollen werden abgewiesen
|
||||
- Die Grundrolle ist nicht vergebbar
|
||||
<!-- testen -->
|
||||
- Benutzerliste öffnen
|
||||
- Formular ausfüllen
|
||||
- Rollen ankreuzen
|
||||
- Erstellen
|
||||
- Benutzer in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer bearbeiten
|
||||
<!-- regeln -->
|
||||
- Leeres Passwortfeld ändert nichts
|
||||
- Die oberste Rolle entzieht sich niemand selbst
|
||||
- Namen enden bei 100 Zeichen
|
||||
- Abteilung endet bei 120 Zeichen
|
||||
<!-- testen -->
|
||||
- Benutzerliste öffnen
|
||||
- LMB auf Bearbeiten
|
||||
- Felder ändern
|
||||
- Speichern
|
||||
- Änderung in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer umschalten
|
||||
<!-- ziel -->
|
||||
Sperrt oder öffnet den Zugang sofort
|
||||
<!-- regeln -->
|
||||
- Bestehende Rollen bleiben erhalten
|
||||
<!-- testen -->
|
||||
- Benutzerliste öffnen
|
||||
- LMB auf Zustand
|
||||
- Bestätigen
|
||||
- Zustandsspalte wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Benutzer im Terminal anlegen
|
||||
<!-- regeln -->
|
||||
- Doppelte E-Mail wird abgewiesen
|
||||
- Die Eingabe erfolgt abgefragt
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Angaben eintragen
|
||||
- Benutzer angelegt
|
||||
117
daten/MtoRagSystem/betriebspruefung.md
Normal file
@@ -0,0 +1,117 @@
|
||||
<!-- titel -->
|
||||
Betriebsprüfung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Bewertet Betriebsreife vor der Abnahme
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Jede Prüfung liest nur lokale Angaben
|
||||
- Kein Chat, kein Shop, kein Modell läuft
|
||||
- Ein Fehler setzt den Gesamtstand
|
||||
- Ein fehlender Nachweis wird zur Warnung
|
||||
- Ein Nachweis wird nie stillschweigend angenommen
|
||||
- Geheimnisse bleiben Verweise
|
||||
- Der Restore-Nachweis bleibt Betreiberaufgabe
|
||||
- Das System richtet keine Zeitsteuerung ein
|
||||
- Jedes Ergebnis landet bereinigt im Protokoll
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Betrieb überblicken
|
||||
<!-- ziel -->
|
||||
Fasst alle Prüfstände und die letzte Sicherung
|
||||
<!-- regeln -->
|
||||
- Die Seite bewertet bei jedem Aufruf neu
|
||||
- Nur ausgelöste Prüfungen landen im Protokoll
|
||||
- Der nächste sinnvolle Schritt steht dabei
|
||||
<!-- testen -->
|
||||
- Menüeintrag Betrieb wählen
|
||||
- Gesamtstand und Teilstände sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherheit prüfen
|
||||
<!-- ziel -->
|
||||
Prüft Rollen, Geheimnisse und Grenzen
|
||||
<!-- regeln -->
|
||||
- Die Prüfung ersetzt kein externes Audit
|
||||
- Geheimniswerte werden nicht gelesen
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Sicherheit prüfen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherungsweg prüfen
|
||||
<!-- ziel -->
|
||||
Bewertet Pfad, Umfang und Restore-Nachweis
|
||||
<!-- regeln -->
|
||||
- Es entsteht keine Sicherung
|
||||
- Ein Restore-Erfolg wird nicht behauptet
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Sicherungsweg prüfen
|
||||
- Prüfpunkte sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Zeitsteuerung prüfen
|
||||
<!-- ziel -->
|
||||
Bewertet Automatik, Turnus und Betreibernachweise
|
||||
<!-- regeln -->
|
||||
- Der Betreiber dokumentiert Automatik selbst
|
||||
- Nicht beschreibbare Pfade erzeugen Hinweise
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Zeitsteuerung prüfen
|
||||
- Nachweistabelle sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Protokoll einsehen
|
||||
<!-- ziel -->
|
||||
Zeigt die zuletzt ausgelösten Prüfungen
|
||||
<!-- regeln -->
|
||||
- Keine Prompts und keine Rohantworten
|
||||
- Keine Geheimnisse und keine Zugangsdaten
|
||||
- Der Text endet bei 220 Zeichen
|
||||
- Höchstens 50 Einträge bleiben erhalten
|
||||
- Die Anzeige zeigt die letzten acht
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- Protokollbereich lesen
|
||||
- Letzte Prüfungen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Abnahmebericht ausgeben
|
||||
<!-- ziel -->
|
||||
Lädt den bereinigten Bericht zur Abnahme
|
||||
<!-- regeln -->
|
||||
- Zwei Formate: JSON und Markdown
|
||||
- Die Datengrenze steht im Bericht
|
||||
- Erledigte Aufgaben fallen weg
|
||||
- Der Export startet keine Prüfung
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- Format wählen
|
||||
- Bericht im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Betriebsreife im Terminal prüfen
|
||||
<!-- regeln -->
|
||||
- Nur ein grüner Stand endet ohne Fehler
|
||||
- Warnungen ändern den Ausgang nicht
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Fallliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Unterlagen öffnen
|
||||
<!-- ziel -->
|
||||
Zeigt Runbook und Checklisten im Adminbereich
|
||||
<!-- regeln -->
|
||||
- Nur Markdown aus dem Projektverzeichnis
|
||||
- Die Anzeige ist rein lesend
|
||||
<!-- testen -->
|
||||
- Menüeintrag Leitfäden wählen
|
||||
- Dokument wählen
|
||||
- Inhalt sichtbar
|
||||
51
daten/MtoRagSystem/claim.md
Normal file
@@ -0,0 +1,51 @@
|
||||
<!-- titel -->
|
||||
Claim
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Prüft einzelne Aussagen der Antwort gegen Belege
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Geprüft werden Werte, Preise und Artikelnummern
|
||||
- Geprüft werden URLs und Rollencodes
|
||||
- Geprüft werden Relationen und Kompatibilitätsaussagen
|
||||
- Ein Claim ohne Quelle gilt als unbelegt
|
||||
- Ein unbelegter Claim setzt ein Prüfsignal
|
||||
- Unbelegte Claims werden benannt
|
||||
- Höchstens fünf Beispiele erscheinen
|
||||
- Rollencodes gelten nur bei genauer Übereinstimmung
|
||||
- Relationen brauchen beide Partner in einem Dokument
|
||||
- Eine leere Antwort gilt als ungeprüft
|
||||
- Sieben Claim-Arten stehen fest
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Antwort bewerten
|
||||
<!-- ziel -->
|
||||
Meldet falsche Zuordnung oder Quellenfehler zurück
|
||||
<!-- regeln -->
|
||||
- Zwei Werte: zustimmend und ablehnend
|
||||
- Ablehnung erlaubt einen Kommentar
|
||||
- Kommentar wird auf 2000 Zeichen gekürzt
|
||||
- Bewertung braucht eine fertige Antwort
|
||||
- Eine fremde Antwort wird abgewiesen
|
||||
- Die Oberfläche sperrt nach dem Speichern
|
||||
- Ein erneuter Aufruf überschreibt die Bewertung
|
||||
- Frage und Antwort werden mitgespeichert
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf eine Bewertung
|
||||
- Bestätigung sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Prompt kopieren
|
||||
<!-- ziel -->
|
||||
Übernimmt die eigene Frage in die Zwischenablage
|
||||
<!-- regeln -->
|
||||
- Kopiert wird nur der Fragetext
|
||||
- Erfolg wird kurz gemeldet
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf Kopieren
|
||||
- Rückmeldung an der Schaltfläche
|
||||
84
daten/MtoRagSystem/diagnose.md
Normal file
@@ -0,0 +1,84 @@
|
||||
<!-- titel -->
|
||||
Diagnose
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Untersucht einzelne Teile des Antwortwegs
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Diagnosen ändern Antwortgüte und Wahrheitssicherung nicht
|
||||
- Prompts und Rohantworten werden nie ausgegeben
|
||||
- Betriebsfunktionen beeinflussen die Antwort nicht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Im Terminal fragen
|
||||
<!-- ziel -->
|
||||
Stellt Fragen an das System ohne Oberfläche
|
||||
<!-- regeln -->
|
||||
- Die Antwort läuft in Stücken ein
|
||||
- Statusmeldungen stehen dazwischen
|
||||
- Der Lauf löst echte Modellaufrufe aus
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Frage eintragen
|
||||
- Antwort läuft ein
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Suchweg testen
|
||||
<!-- ziel -->
|
||||
Prüft den hybriden Suchweg zu einer Frage
|
||||
<!-- regeln -->
|
||||
- Leere Frage wird abgewiesen
|
||||
- Die Ausgabe nennt Dauer und Trefferzahl
|
||||
<!-- testen -->
|
||||
- Kommando mit Frage aufrufen
|
||||
- Trefferliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Faktenabdeckung prüfen
|
||||
<!-- ziel -->
|
||||
Prüft, wie gut Fakten eine Frage abdecken
|
||||
<!-- regeln -->
|
||||
- Eine leere Frage wird abgewiesen
|
||||
- Eine Mindestgüte ist wählbar
|
||||
<!-- testen -->
|
||||
- Kommando mit Frage aufrufen
|
||||
- Abdeckung mit Zusammenfassung sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Ankerauflösung testen
|
||||
<!-- ziel -->
|
||||
Prüft die Auflösung einer Folgefrage trocken
|
||||
<!-- regeln -->
|
||||
- Kein Eingriff in die Laufzeit
|
||||
- Mehrdeutige Anker werden verworfen
|
||||
- Eine genannte Artikelnummer schlägt jeden Anker
|
||||
<!-- testen -->
|
||||
- Kommando mit Folgefrage aufrufen
|
||||
- Auflösungsbericht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Verlaufsanker auslesen
|
||||
<!-- ziel -->
|
||||
Zieht Bezugsanker aus einem Gesprächsverlauf
|
||||
<!-- regeln -->
|
||||
- Anker belegen keine Fachwerte
|
||||
- Eingabe per Argument, Datei oder Strom
|
||||
- Ein eingebauter Rauchtest ist wählbar
|
||||
<!-- testen -->
|
||||
- Kommando mit Rauchtest aufrufen
|
||||
- Ankerliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Fakten inspizieren
|
||||
<!-- ziel -->
|
||||
Untersucht gespeicherte Fakten der Chunkdatei
|
||||
<!-- regeln -->
|
||||
- Eine fehlende Chunkdatei meldet einen Fehler
|
||||
- Nur lesender Zugriff auf den Index
|
||||
- Filter nach Text, Typ und Anzahl
|
||||
<!-- testen -->
|
||||
- Kommando mit Suchtext aufrufen
|
||||
- Trefferliste sichtbar
|
||||
107
daten/MtoRagSystem/dokument.md
Normal file
@@ -0,0 +1,107 @@
|
||||
<!-- titel -->
|
||||
Dokument
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Führt eine Wissensquelle über ihre Versionen
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein Dokument hält mehrere Versionen
|
||||
- Genau eine Version ist aktiv
|
||||
- Tags hängen am Dokument, nicht an der Version
|
||||
- Schreiben an Dokument oder Version ändert den Index nicht
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Dokumente filtern
|
||||
<!-- ziel -->
|
||||
Grenzt die Liste nach Zustand und Pflege ein
|
||||
<!-- regeln -->
|
||||
- Sechs Filter: Suche, Status, Index, Version, Titel, Tags
|
||||
- Unbekannter Filterwert fällt auf alle
|
||||
- Die Suche trifft Titel, Kennung und Dateiname
|
||||
- Kennzahlen zählen immer den Gesamtbestand
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- Filter setzen
|
||||
- LMB auf Filtern
|
||||
- Trefferzahl sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Dokument hochladen
|
||||
<!-- ziel -->
|
||||
Legt eine Wissensquelle mit erster Version an
|
||||
<!-- regeln -->
|
||||
- Die Datei ist Pflicht
|
||||
- Ohne Titel dient der Dateiname als Titel
|
||||
- Ein schwacher Titel bekommt einen Prüfhinweis
|
||||
- Version eins entsteht aktiv
|
||||
- Je Version wird eine Prüfsumme gespeichert
|
||||
- Der Index bleibt bis zum Neuaufbau unverändert
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- LMB auf neues Dokument
|
||||
- Datei wählen
|
||||
- Speichern
|
||||
- Dokumentseite sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Titel ändern
|
||||
<!-- ziel -->
|
||||
Ersetzt einen schwachen Titel fachlich
|
||||
<!-- regeln -->
|
||||
- Leerer Titel wird abgewiesen
|
||||
- Höchstens 255 Zeichen
|
||||
- Der Prüfhinweis entfällt danach
|
||||
- Index und Antwortlogik bleiben unberührt
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- Titel ändern
|
||||
- Speichern
|
||||
- Titel als geprüft markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Titel vorschlagen lassen
|
||||
<!-- ziel -->
|
||||
Erzeugt Titelkandidaten aus dem Dokumentanfang
|
||||
<!-- regeln -->
|
||||
- Der Ausschnitt endet bei 9000 Zeichen
|
||||
- Höchstens sechs Vorschläge
|
||||
- Höchstens 120 Zeichen je Vorschlag
|
||||
- Zu kurze Kandidaten fallen weg
|
||||
- Ein Klick füllt nur das Feld
|
||||
- Dokument, Version und Index bleiben unberührt
|
||||
<!-- testen -->
|
||||
- Dokumentseite öffnen
|
||||
- LMB auf Titel vorschlagen
|
||||
- Kandidat wählen
|
||||
- Titelfeld gefüllt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Indexbereitschaft ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt, was den Index bisher nicht erreicht hat
|
||||
<!-- regeln -->
|
||||
- Offene Änderungen werden gezählt
|
||||
- Gelöschte Dokumente im Index werden benannt
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- Bereitschaftsblock lesen
|
||||
- Zahl offener Änderungen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Dokument löschen
|
||||
<!-- ziel -->
|
||||
Entfernt Dokument, Versionen und Dateien endgültig
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf löschen
|
||||
- Ein laufender Neuaufbau verhindert das Löschen
|
||||
- Versionsdateien werden mitgelöscht
|
||||
- Ein Auftrag hält den Vorgang fest
|
||||
- Der Index ändert sich beim nächsten Neuaufbau
|
||||
<!-- testen -->
|
||||
- Dokumentliste öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Dokument verschwindet
|
||||
77
daten/MtoRagSystem/evalfall.md
Normal file
@@ -0,0 +1,77 @@
|
||||
<!-- titel -->
|
||||
Evalfall
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Beschreibt einen prüfbaren Fall für die Antwortgüte
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Neun Falltypen stehen im Adminbereich
|
||||
- Ein zehnter Typ läuft nur im Terminal
|
||||
- Eine Fallkennung ist projektweit eindeutig
|
||||
- Pflichtfelder sind Kennung, Typ und Frage
|
||||
- Fälle liegen als Zeilendatei je Typ und Bereich
|
||||
- Schreiben erfolgt mit ausschließender Sperre
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Bereich wählen
|
||||
<!-- ziel -->
|
||||
Schaltet zwischen Systembasis und Fachbereich
|
||||
<!-- regeln -->
|
||||
- Der Bereich prägt jede weitere Handlung
|
||||
- Fachbereiche liegen in eigenen Ordnern
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf einen Bereichsreiter
|
||||
- Fälle des Bereichs sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evalfall anlegen
|
||||
<!-- regeln -->
|
||||
- Doppelte Kennung wird abgewiesen
|
||||
- Erwartung muss ein Objekt sein
|
||||
- Verlauf muss eine Liste sein
|
||||
- Ein Fehler verhindert jede Änderung
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf neuer Test
|
||||
- Formular ausfüllen
|
||||
- Absenden
|
||||
- Fall in der Datei
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evalfall geführt anlegen
|
||||
<!-- ziel -->
|
||||
Legt einen Fall über einen Assistenten an
|
||||
<!-- regeln -->
|
||||
- Eigener Entwurf mit eigener Fehlerprüfung
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf Assistent
|
||||
- Schritte ausfüllen
|
||||
- Fall in der Datei
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evalfall ableiten
|
||||
<!-- ziel -->
|
||||
Übernimmt einen gescheiterten Lauf als Fall
|
||||
<!-- regeln -->
|
||||
- Kennung und Frage werden vorbelegt
|
||||
<!-- testen -->
|
||||
- Lauf mit Fehlschlag öffnen
|
||||
- LMB auf Fall übernehmen
|
||||
- Formular vorbefüllt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evalfall löschen
|
||||
<!-- regeln -->
|
||||
- Eine defekte Zeile verhindert die Änderung
|
||||
- Unbekannte Kennung meldet einen Fehler
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Seite neuer Test öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Fall verschwindet
|
||||
100
daten/MtoRagSystem/evallauf.md
Normal file
@@ -0,0 +1,100 @@
|
||||
<!-- titel -->
|
||||
Evallauf
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Prüft die Antwortpipeline gegen gespeicherte Fälle
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein gescheiterter Fall setzt den Gesamtstand
|
||||
- Eine leere Auswahl gilt nicht als Fehlschlag
|
||||
- Berichte entstehen unteilbar
|
||||
- Evals messen Fälle, nicht jede mögliche Frage
|
||||
- Fünf Falltypen rufen das Modell
|
||||
- Vier Falltypen laufen ohne Modell
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evallauf starten
|
||||
<!-- ziel -->
|
||||
Führt Fälle aus dem Adminbereich aus
|
||||
<!-- regeln -->
|
||||
- Der Lauf braucht die Wissensrolle
|
||||
- Der Bericht wird zusätzlich archiviert
|
||||
- Der Lauf blockiert die Anfrage bis zum Ende
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- Auswahl treffen
|
||||
- Lauf starten
|
||||
- Ergebnis je Fall sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Einzelfall erneut testen
|
||||
<!-- ziel -->
|
||||
Wiederholt genau einen gescheiterten Fall
|
||||
<!-- regeln -->
|
||||
- Nur der gewählte Fall läuft
|
||||
<!-- testen -->
|
||||
- Lauf mit Fehlschlag öffnen
|
||||
- LMB auf erneut testen
|
||||
- Ergebnis des Falls sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Läufe vergleichen
|
||||
<!-- ziel -->
|
||||
Stellt zwei Berichte als Unterschied gegenüber
|
||||
<!-- regeln -->
|
||||
- Der Vergleich nennt behoben, neu und entfernt
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- Vergleichsbasis wählen
|
||||
- Unterschied sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evallauf im Terminal ausführen
|
||||
<!-- regeln -->
|
||||
- Die Auswahl folgt Typ und Bereich
|
||||
- Ein Abbruch nach dem ersten Fehler ist wählbar
|
||||
- Ein Lauf ohne Schreiben ist wählbar
|
||||
- Fälle lassen sich nur auflisten
|
||||
<!-- testen -->
|
||||
- Kommando mit Typ aufrufen
|
||||
- Ergebnis je Fall sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Evallauf parallelisieren
|
||||
<!-- ziel -->
|
||||
Verteilt Fälle auf mehrere Kindprozesse
|
||||
<!-- regeln -->
|
||||
- Zwischen einem und 32 Prozessen
|
||||
- Vorgabe sind zwei Prozesse
|
||||
- Ein Zeitlimit je Prozess ist wählbar
|
||||
- Das Ergebnis ist ein Sammelbericht
|
||||
<!-- testen -->
|
||||
- Kommando mit Prozesszahl aufrufen
|
||||
- Sammelbericht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Berichte aufräumen
|
||||
<!-- regeln -->
|
||||
- Nur erzeugte Dateinamen fallen weg
|
||||
- Aufräumen behält 20 Läufe je Bereich
|
||||
- Die Liste zeigt zehn Läufe
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf Aufräumen
|
||||
- Berichtszahl sinkt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Berichte löschen
|
||||
<!-- ziel -->
|
||||
Entfernt alle Läufe eines Bereichs
|
||||
<!-- regeln -->
|
||||
- Der aktuelle Lauf fällt mit weg
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Menüeintrag Eval Suite wählen
|
||||
- LMB auf alle löschen
|
||||
- Bestätigen
|
||||
- Berichtsliste leer
|
||||
138
daten/MtoRagSystem/fremdinhalt.md
Normal file
@@ -0,0 +1,138 @@
|
||||
<!-- titel -->
|
||||
Fremdinhalt
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Prüft externe Inhalte vor jeder Nutzung
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Geprüft wird der ausgewählte Inhalt
|
||||
- Ein Lesen führt kein Werkzeug aus
|
||||
- Ein Lesen ändert die Antwortpipeline nicht
|
||||
- Vorschauen sind gekürzt und bereinigt
|
||||
- Externe Inhalte heben ihren Rang nicht selbst
|
||||
- Der Bereich braucht die höchste Rolle
|
||||
- Keine Übernahme ins Standardwissen erfolgt automatisch
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt live prüfen
|
||||
<!-- ziel -->
|
||||
Liest den ausgewählten Inhalt einmalig online
|
||||
<!-- regeln -->
|
||||
- Nur der gewählte Inhalt wird gelesen
|
||||
- Ohne Zutun wird nichts gespeichert
|
||||
<!-- testen -->
|
||||
- Übersicht öffnen
|
||||
- LMB auf Inhalt prüfen
|
||||
- Bestätigen
|
||||
- Vorschau mit Abrufzahl
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt bereitstellen
|
||||
<!-- ziel -->
|
||||
Merkt einen gelesenen Inhalt als Kandidat vor
|
||||
<!-- regeln -->
|
||||
- Chat und Antwortnutzung bleiben aus
|
||||
- Der Kandidat startet ohne Freigabe
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Inhalt live prüfen
|
||||
- LMB auf bereitstellen
|
||||
- Bestätigen
|
||||
- Kandidat in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt auswählen
|
||||
<!-- ziel -->
|
||||
Ordnet einen Inhalt einem Raum zur Prüfung zu
|
||||
<!-- regeln -->
|
||||
- Zwei Arten: eigener Raum und Ergänzung
|
||||
- Die Auswahl gilt schon als geprüft
|
||||
- Die Auswahl schaltet den Chat nicht ein
|
||||
- Standardwissen wird dadurch nicht ergänzt
|
||||
<!-- testen -->
|
||||
- Räume überblicken
|
||||
- LMB auf Inhalt auswählen
|
||||
- Bestätigen
|
||||
- Inhalt im Freigabebereich
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt entscheiden
|
||||
<!-- ziel -->
|
||||
Gibt einen geprüften Inhalt frei oder stellt zurück
|
||||
<!-- regeln -->
|
||||
- Fünf Wege bis zum Zurücksetzen
|
||||
- Eine unbekannte Entscheidung wird abgewiesen
|
||||
- Eine Freigabe schaltet den Chat nicht ein
|
||||
- Die Notiz endet bei 1000 Zeichen
|
||||
<!-- testen -->
|
||||
- Freigabebereich öffnen
|
||||
- LMB auf Inhalt ansehen
|
||||
- Entscheidung wählen
|
||||
- Zustandsmarke wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Inhalt im Chat einschalten
|
||||
<!-- ziel -->
|
||||
Fügt einen freigegebenen Inhalt dem Raum zu
|
||||
<!-- regeln -->
|
||||
- Nur geprüfte Inhalte eines eigenen Raums
|
||||
- Nicht vorbereitete Inhalte werden abgewiesen
|
||||
- Suche und Belege bleiben unberührt
|
||||
- Es entsteht kein gespeichertes Wissen
|
||||
<!-- testen -->
|
||||
- Freigabebereich öffnen
|
||||
- LMB auf im Chat einschalten
|
||||
- Inhalt als aktiv markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Kandidaten filtern
|
||||
<!-- ziel -->
|
||||
Grenzt vorbereitete Inhalte nach Zustand ein
|
||||
<!-- regeln -->
|
||||
- Filter nach Zustand, Anbindung, Art und Zeit
|
||||
- Das Filtern ruft nichts extern ab
|
||||
<!-- testen -->
|
||||
- Vorbereitete Inhalte öffnen
|
||||
- Filter setzen
|
||||
- Trefferliste eingegrenzt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Kandidat entfernen
|
||||
<!-- ziel -->
|
||||
Löscht einen vorbereiteten Inhalt endgültig
|
||||
<!-- regeln -->
|
||||
- Die Vorschau fällt mit weg
|
||||
<!-- testen -->
|
||||
- Vorbereitete Inhalte öffnen
|
||||
- LMB auf Entfernen
|
||||
- Kandidat verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Kandidaten ausgeben
|
||||
<!-- ziel -->
|
||||
Lädt vorbereitete Inhalte als Datei herunter
|
||||
<!-- regeln -->
|
||||
- Zwei Formate: Markdown und JSONL
|
||||
- Der Export gibt die gefilterte Menge aus
|
||||
- Der Export wirkt nicht als Freigabe
|
||||
<!-- testen -->
|
||||
- Vorbereitete Inhalte öffnen
|
||||
- Format wählen
|
||||
- Herunterladen
|
||||
- Datei im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Ressource lesen
|
||||
<!-- ziel -->
|
||||
Liest eine freigegebene Ressource im Terminal
|
||||
<!-- regeln -->
|
||||
- Nur erlaubte Server und Adressen
|
||||
- Der Inhalt wird bereinigt
|
||||
- Ausgegeben werden nur Metadaten und Prüfsumme
|
||||
- Eine Kürzung wird gekennzeichnet
|
||||
<!-- testen -->
|
||||
- Kommando mit Adresse aufrufen
|
||||
- Metadaten und Prüfsumme sichtbar
|
||||
64
daten/MtoRagSystem/indexprofil.md
Normal file
@@ -0,0 +1,64 @@
|
||||
<!-- titel -->
|
||||
Indexprofil
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Legt Struktur für Chunking und Einbettung fest
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Ein Profil ist unveränderlich
|
||||
- Genau ein Profil ist aktiv
|
||||
- Einsehen braucht die Wissensrolle
|
||||
- Ändern braucht die höchste Rolle
|
||||
- Die Version zählt beim Anlegen hoch
|
||||
- Ein neues Profil entsteht inaktiv
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profile prüfen
|
||||
<!-- ziel -->
|
||||
Gleicht das aktive Profil gegen den Index ab
|
||||
<!-- regeln -->
|
||||
- Der Vergleich läuft gegen die Indexmetadaten
|
||||
- Eine abweichende Zeile setzt den Gesamtstand
|
||||
- Fehlende Metadaten gelten als Strukturabweichung
|
||||
- Die Ansicht startet keinen Neuaufbau
|
||||
<!-- testen -->
|
||||
- Menüeintrag Indexprofile wählen
|
||||
- Abweichungen je Zeile sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil anlegen
|
||||
<!-- regeln -->
|
||||
- Chunkgröße von 50 bis 1000 in Schritten von 25
|
||||
- Überlappung von 25 bis 200 in Schritten von 25
|
||||
- Das Einbettungsmodell ist Pflicht
|
||||
- Fehlende Pflichtwerte nennen das Feld
|
||||
- Nur die höchste Rolle darf anlegen
|
||||
<!-- testen -->
|
||||
- Indexprofile öffnen
|
||||
- Werte eintragen
|
||||
- Profil erstellen
|
||||
- Inaktives Profil sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil aktivieren
|
||||
<!-- regeln -->
|
||||
- Das bisherige Profil wird deaktiviert
|
||||
- Die Aktivierung startet keinen Neuaufbau
|
||||
<!-- testen -->
|
||||
- Indexprofile öffnen
|
||||
- LMB auf Aktivieren
|
||||
- Bestätigen
|
||||
- Profil als aktiv markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil löschen
|
||||
<!-- regeln -->
|
||||
- Der Löschweg erscheint nur bei inaktiven Profilen
|
||||
<!-- testen -->
|
||||
- Indexprofile öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Profil verschwindet
|
||||
46
daten/MtoRagSystem/konfiguration.md
Normal file
@@ -0,0 +1,46 @@
|
||||
<!-- titel -->
|
||||
Konfiguration
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Prüft die wirksamen Einstellungen vor dem Betrieb
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Fachsemantik gehört in die Konfiguration
|
||||
- Harte Sonderpfade im Antwortkern sind verboten
|
||||
- Geänderter Kataloginhalt wirkt ohne Codeänderung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Konfiguration validieren
|
||||
<!-- regeln -->
|
||||
- Fehler und Warnungen erscheinen getrennt
|
||||
- Warnungen ändern den Ausgang nicht
|
||||
- Regressionswächter melden nur Warnungen
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Fehler- und Warnliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Konfiguration ausgeben
|
||||
<!-- ziel -->
|
||||
Zeigt die aufgelöste Einstellung zur Diagnose
|
||||
<!-- regeln -->
|
||||
- Die Ausgabe ist nicht bereinigt
|
||||
- Pfade und Adressen stehen darin
|
||||
- Nur der Shopschlüssel bleibt verborgen
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Vollständige Ausgabe sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Quellen auditieren
|
||||
<!-- ziel -->
|
||||
Prüft Herkunft, Muster und Fachneutralität
|
||||
<!-- regeln -->
|
||||
- Reine Quelltextanalyse ohne Laufzeitwirkung
|
||||
- Ein Fehlerstand beendet den Lauf
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Kennzahlen und Funde sichtbar
|
||||
68
daten/MtoRagSystem/modellprofil.md
Normal file
@@ -0,0 +1,68 @@
|
||||
<!-- titel -->
|
||||
Modellprofil
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Stellt Modell und Suchparameter der Antwort ein
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Höchstens ein Profil ist systemweit aktiv
|
||||
- Ohne aktives Profil greifen die Vorgabewerte
|
||||
- Die Version zählt je Modellname hoch
|
||||
- Ein neues Profil entsteht inaktiv
|
||||
- Ein aktives Profil lässt sich nicht löschen
|
||||
- Nur fehlende Felder erben die Vorgabewerte
|
||||
- Wertebereiche greifen erst beim Aktivieren
|
||||
- Suchwerte werden still auf 1 bis 200 begrenzt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profile auflisten
|
||||
<!-- regeln -->
|
||||
- Das aktive Profil steht oben
|
||||
- Die Anzeige startet keine Erzeugung
|
||||
<!-- testen -->
|
||||
- Menüeintrag Modellsetup wählen
|
||||
- Profilliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil erstellen
|
||||
<!-- regeln -->
|
||||
- Der Modellname ist Pflicht
|
||||
- Nur die höchste Rolle darf anlegen
|
||||
<!-- testen -->
|
||||
- Profilliste öffnen
|
||||
- Werte eintragen
|
||||
- Absenden
|
||||
- Inaktives Profil sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil aktivieren
|
||||
<!-- testen -->
|
||||
- Profilliste öffnen
|
||||
- LMB auf Aktivieren
|
||||
- Bestätigen
|
||||
- Profil als aktiv markiert
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Profil löschen
|
||||
<!-- testen -->
|
||||
- Profilliste öffnen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Profil verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Suche testen
|
||||
<!-- ziel -->
|
||||
Prüft das Trefferverhalten eines Profils
|
||||
<!-- regeln -->
|
||||
- Leere Frage liefert kein Ergebnis
|
||||
- Der Test ändert das Profil nicht
|
||||
- Der Test aktiviert das Profil nicht
|
||||
<!-- testen -->
|
||||
- Profilliste öffnen
|
||||
- LMB auf Testen
|
||||
- Frage eintragen
|
||||
- Trefferliste sichtbar
|
||||
43
daten/MtoRagSystem/protokoll.md
Normal file
@@ -0,0 +1,43 @@
|
||||
<!-- titel -->
|
||||
Protokoll
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Zeigt Betriebsmeldungen der Dienste
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf lesen
|
||||
- Die Anzeige ist rein lesend
|
||||
- Kein Löschen ist vorgesehen
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Protokolle auflisten
|
||||
<!-- regeln -->
|
||||
- Nur Dateien nach festem Namensmuster
|
||||
- Neueste Änderung steht oben
|
||||
<!-- testen -->
|
||||
- Menüeintrag Protokolle wählen
|
||||
- Dateiliste mit Größe sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Protokoll anzeigen
|
||||
<!-- regeln -->
|
||||
- Höchstens 1000 Zeilen
|
||||
- Gelesen wird vom Dateiende
|
||||
- Eine fehlende Datei meldet einen Fehler
|
||||
<!-- testen -->
|
||||
- Protokollliste öffnen
|
||||
- LMB auf Anzeigen
|
||||
- Letzte Zeilen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Vektorprotokoll anzeigen
|
||||
<!-- regeln -->
|
||||
- Feste Quelle im Protokollverzeichnis
|
||||
- Höchstens 500 Zeilen
|
||||
- Eine fehlende Datei meldet einen Hinweis
|
||||
<!-- testen -->
|
||||
- Menüeintrag Vektorprotokoll wählen
|
||||
- Letzte Zeilen sichtbar
|
||||
99
daten/MtoRagSystem/rueckmeldung.md
Normal file
@@ -0,0 +1,99 @@
|
||||
<!-- titel -->
|
||||
Rückmeldung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Sammelt Nutzerkritik für die Verbesserung
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Eine Rückmeldung hängt an einer Antwort
|
||||
- Die Adminsicht braucht die Wissensrolle
|
||||
- Ein Löschen ist endgültig
|
||||
- Der Export enthält Frage und Antwort im Klartext
|
||||
- Der Export folgt den gesetzten Filtern
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldungen filtern
|
||||
<!-- ziel -->
|
||||
Grenzt Fälle nach zehn Merkmalen ein
|
||||
<!-- regeln -->
|
||||
- Filter nach Bewertung und Bearbeitungsstand
|
||||
- Filter nach Einordnung und Fehlerverdacht
|
||||
- Filter nach Vorrang und Referenzwert
|
||||
- Seitengröße wählbar mit 25, 50 oder 100
|
||||
<!-- testen -->
|
||||
- Menüeintrag Chat-Feedback wählen
|
||||
- Filter setzen
|
||||
- Trefferliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldung ansehen
|
||||
<!-- ziel -->
|
||||
Zeigt einen Fall mit Frage und Antwort
|
||||
<!-- testen -->
|
||||
- Rückmeldungen filtern
|
||||
- LMB auf einen Fall
|
||||
- Frage und Antwort sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldung erledigen
|
||||
<!-- regeln -->
|
||||
- Eine Notiz ist möglich
|
||||
<!-- testen -->
|
||||
- Rückmeldung ansehen
|
||||
- LMB auf erledigt
|
||||
- Zustand wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldung wieder öffnen
|
||||
<!-- testen -->
|
||||
- Erledigte Rückmeldung ansehen
|
||||
- LMB auf wieder öffnen
|
||||
- Zustand wechselt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldungen gesammelt erledigen
|
||||
<!-- ziel -->
|
||||
Setzt den Stand für die ganze Auswahl
|
||||
<!-- regeln -->
|
||||
- Auswahl über Kästchen oder Filter
|
||||
- Höchstens 5000 Fälle je Aktion
|
||||
<!-- testen -->
|
||||
- Rückmeldungen filtern
|
||||
- Auswahl treffen
|
||||
- LMB auf Auswahl erledigen
|
||||
- Zustände wechseln
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldung löschen
|
||||
<!-- testen -->
|
||||
- Rückmeldung ansehen
|
||||
- LMB auf Löschen
|
||||
- Bestätigen
|
||||
- Eintrag verschwindet
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldungen ausgeben
|
||||
<!-- regeln -->
|
||||
- Zwei Formate: Markdown und JSONL
|
||||
- Der Export ist nicht bereinigt
|
||||
- Vorgefertigte Auszüge je Vorrang
|
||||
<!-- testen -->
|
||||
- Rückmeldungen filtern
|
||||
- Format wählen
|
||||
- Datei im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Rückmeldungen einordnen
|
||||
<!-- ziel -->
|
||||
Bestimmt Typ, Risiko und Vorrang im Terminal
|
||||
<!-- regeln -->
|
||||
- Ohne Erzwingen nur ungeordnete Einträge
|
||||
- Höchstens 5000 Einträge je Lauf
|
||||
- Vorgabe sind 500 Einträge
|
||||
- Zwischenstände werden gespeichert
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Zähler je Risiko sichtbar
|
||||
76
daten/MtoRagSystem/selbsttest.md
Normal file
@@ -0,0 +1,76 @@
|
||||
<!-- titel -->
|
||||
Selbsttest
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Sichert Grenzen des Systems gegen Rückschritte
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- 23 Selbsttests decken die Regressionsfläche
|
||||
- Jeder Test hat sein eigenes Kommando
|
||||
- Es gibt kein Sammelkommando
|
||||
- Jeder Test liefert Fallliste und Ausgang
|
||||
- Jeder Test kennt eine maschinenlesbare Ausgabe
|
||||
- 15 Tests prüfen nur den Quelltext
|
||||
- Sechs Tests prüfen gemischt
|
||||
- Zwei Tests prüfen nur Verhalten
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Einzeltest ausführen
|
||||
<!-- ziel -->
|
||||
Prüft eine benannte Grenze des Systems
|
||||
<!-- regeln -->
|
||||
- Kein Modell, kein Netz, keine Antwort
|
||||
- Keine Datenbank und kein Import
|
||||
- Ein gescheiterter Fall beendet den Lauf
|
||||
<!-- testen -->
|
||||
- Kommandonamen aus der Übersicht holen
|
||||
- Kommando aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Ingestgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Sichert Markdown, Chunks und Batchgrenzen ab
|
||||
<!-- regeln -->
|
||||
- Zwölf Kommandos decken diesen Bereich
|
||||
- Ein Test räumt sein Verzeichnis selbst auf
|
||||
<!-- testen -->
|
||||
- Kommando aus der Ingestgruppe aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Anbindungsgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Sichert Fremddaten und Werkzeuggrenzen ab
|
||||
<!-- regeln -->
|
||||
- Drei Kommandos decken diesen Bereich
|
||||
- Verbotene Zeichenketten gelten als Fall
|
||||
<!-- testen -->
|
||||
- Kommando aus der Anbindungsgruppe aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Architekturgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Sichert Flussgrenzen und Produktregeln ab
|
||||
<!-- regeln -->
|
||||
- Fünf Kommandos decken diesen Bereich
|
||||
- Ein Test hängt an einer Freigabeversion
|
||||
<!-- testen -->
|
||||
- Kommando aus der Architekturgruppe aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Antwortgrenzen prüfen
|
||||
<!-- ziel -->
|
||||
Sichert Anker, Prüfung und Raumauswahl ab
|
||||
<!-- regeln -->
|
||||
- Drei Kommandos decken diesen Bereich
|
||||
- Keine Chatantwort und kein Shopzugriff
|
||||
- Unbelegte Begriffe bleiben unrepariert
|
||||
<!-- testen -->
|
||||
- Kommando aus der Antwortgruppe aufrufen
|
||||
- Fallliste mit Ständen sichtbar
|
||||
75
daten/MtoRagSystem/shoptreffer.md
Normal file
@@ -0,0 +1,75 @@
|
||||
<!-- titel -->
|
||||
Shoptreffer
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Liefert Preis und Verfügbarkeit aus dem Shop
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Der Preis stammt allein aus dem Shopdatensatz
|
||||
- Ohne Shoppreis erscheint kein Preis
|
||||
- Ein fehlender Preis wird nicht zu null
|
||||
- Kostenlos gilt nur mit Quellenbeleg
|
||||
- Verfügbarkeit stammt allein aus dem Shopfeld
|
||||
- Die Produktadresse stammt aus dem Shoppfad
|
||||
- Reine Wissensantworten tragen keine Shopadressen
|
||||
- Ein Shoptreffer belegt keine technische Eignung
|
||||
- Zubehör wird nicht als Hauptgerät ausgegeben
|
||||
- Bündelangaben bleiben unzerlegt
|
||||
- Gefilterte Treffer sind keine fehlenden Treffer
|
||||
- Kein Treffer bedeutet nicht: gibt es nicht
|
||||
- Ein Shopausfall wird gemeldet
|
||||
- Bei automatischer Basis startet sie nur bei Kaufbezug
|
||||
- Die Basis Shop erzwingt die Suche
|
||||
- Die gesendete Suchanfrage wird offengelegt
|
||||
- Bilder stammen aus dem Bildfeld desselben Datensatzes
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Shopsuche auslösen
|
||||
<!-- ziel -->
|
||||
Sucht aus einer Wissensantwort passende Produkte
|
||||
<!-- regeln -->
|
||||
- Angebot entfällt bei gleicher Suche
|
||||
- Angebot entfällt bei ablehnender Antwort
|
||||
- Eine erweiterte Suche wird ausgewiesen
|
||||
<!-- testen -->
|
||||
- Frage stellen
|
||||
- LMB auf Shopsuche
|
||||
- Trefferliste sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Preis nachfragen
|
||||
<!-- ziel -->
|
||||
Ruft Handelsdaten zum genannten Produkt ab
|
||||
<!-- regeln -->
|
||||
- Angebot entfällt bei genanntem Preis
|
||||
- Die Folgeantwort bleibt am Produkt
|
||||
<!-- testen -->
|
||||
- Frage nach einem Produkt stellen
|
||||
- LMB auf Preis anzeigen
|
||||
- Preis und Artikelnummer sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Treffer filtern
|
||||
<!-- ziel -->
|
||||
Grenzt die Liste auf Zubehör oder Geräte ein
|
||||
<!-- regeln -->
|
||||
- Angebot erscheint nur bei Wirkung
|
||||
- Mehrdeutige Rollen gelten nicht als Gerät
|
||||
<!-- testen -->
|
||||
- Shopsuche auslösen
|
||||
- LMB auf eine Rolle
|
||||
- Liste eingegrenzt
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Shopsuche diagnostizieren
|
||||
<!-- ziel -->
|
||||
Prüft eine Suchanfrage samt Reparatur im Terminal
|
||||
<!-- regeln -->
|
||||
- Der Zugriff läuft live gegen den Shop
|
||||
- Die Reparatursuche bevorzugt den angefragten Code
|
||||
<!-- testen -->
|
||||
- Kommando mit Suchtext aufrufen
|
||||
- Suchanfrage und Treffer sichtbar
|
||||
90
daten/MtoRagSystem/sicherung.md
Normal file
@@ -0,0 +1,90 @@
|
||||
<!-- titel -->
|
||||
Sicherung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
optional
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Sichert Anwendung und Datenbank nachvollziehbar
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Geheimnisse werden nie mitkopiert
|
||||
- Fremdbibliotheken und Zwischenspeicher bleiben draußen
|
||||
- Ein Datenbankabzug entsteht auf Anforderung oder Vorgabe
|
||||
- Eine Sperrdatei verhindert parallele Läufe
|
||||
- Sieben Stände bleiben rollierend erhalten
|
||||
- Symlinks werden übersprungen
|
||||
- Ein Verzeichnis nennt Umfang und Kennung
|
||||
- Eine gelungene Sicherung beweist keinen Restore
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherung testen
|
||||
<!-- ziel -->
|
||||
Prüft den geplanten Umfang ohne Schreibvorgang
|
||||
<!-- regeln -->
|
||||
- Keine Sicherungsdatei entsteht
|
||||
- Keine alte Sicherung fällt weg
|
||||
- Fehlende Pflichtquellen erscheinen als Warnung
|
||||
- Fehlende Zusatzquellen zählen getrennt
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Sicherung testen
|
||||
- Umfang und Warnungen sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherung starten
|
||||
<!-- regeln -->
|
||||
- Ein Datenbankabzug braucht Schalter oder Vorgabe
|
||||
- Das Verzeichnis nennt keinen Zugang
|
||||
- Geräumte Sicherungen werden benannt
|
||||
- Eine Rückfrage geht voraus
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Sicherung starten
|
||||
- Bestätigen
|
||||
- Sicherung in der Liste
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherung herunterladen
|
||||
<!-- ziel -->
|
||||
Holt ein Archiv für den Restore-Test
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf herunterladen
|
||||
- Nur gültige lokale Kennungen
|
||||
- Der Abruf startet keine Sicherung
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Herunterladen
|
||||
- Archiv im Download
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Restore prüfen
|
||||
<!-- ziel -->
|
||||
Bewertet eine Sicherung als Wiederherstellungsgrundlage
|
||||
<!-- regeln -->
|
||||
- Nur die höchste Rolle darf prüfen
|
||||
- Es läuft keine Wiederherstellung
|
||||
- Kein Datenbankimport erfolgt
|
||||
- Gelesen werden Verzeichnis und Bestandteile
|
||||
- Das Ergebnis liefert einen Plan
|
||||
<!-- testen -->
|
||||
- Betriebsseite öffnen
|
||||
- LMB auf Restore prüfen
|
||||
- Prüfpunkte und Plan sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Sicherung im Terminal erstellen
|
||||
<!-- regeln -->
|
||||
- Ein Trockenlauf schreibt keine Datei
|
||||
- Die Aufbewahrung ist wählbar
|
||||
<!-- testen -->
|
||||
- Kommando aufrufen
|
||||
- Kennung und Umfang sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Restore im Terminal prüfen
|
||||
<!-- regeln -->
|
||||
- Kein Netz, kein Modell, kein Chat
|
||||
<!-- testen -->
|
||||
- Kommando mit Kennung aufrufen
|
||||
- Prüfpunkte und Plan sichtbar
|
||||
83
daten/MtoRagSystem/sitzung.md
Normal file
@@ -0,0 +1,83 @@
|
||||
<!-- titel -->
|
||||
Sitzung
|
||||
----------------------------------------
|
||||
<!-- art -->
|
||||
kern
|
||||
----------------------------------------
|
||||
<!-- ziel -->
|
||||
Hält Zugang und Verlauf einer Unterhaltung
|
||||
----------------------------------------
|
||||
<!-- regeln -->
|
||||
- Chat und Adminbereich teilen eine Anmeldung
|
||||
- Ein Abmelden beendet beide Bereiche
|
||||
- Der Verlauf hängt an einem Browserkennzeichen
|
||||
- Ein Abmelden löscht dieses Kennzeichen nicht
|
||||
- Deaktivierte Konten werden abgewiesen
|
||||
- Der Verlauf löst nur Bezüge auf
|
||||
- Der Verlauf belegt keine Fachwerte
|
||||
- Ein Hinweis nennt Fehlerrisiko und Datennutzung
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Am Chat anmelden
|
||||
<!-- regeln -->
|
||||
- E-Mail und Passwort sind Pflicht
|
||||
- Ohne Chatrolle erscheint eine Verbotsseite
|
||||
- Falscher Zugang behält die E-Mail
|
||||
- Angemeldete landen sofort im Chat
|
||||
<!-- testen -->
|
||||
- Anmeldeseite aufrufen
|
||||
- E-Mail und Passwort eintragen
|
||||
- Bestätigen
|
||||
- Chat mit Verlauf sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Vom Chat abmelden
|
||||
<!-- regeln -->
|
||||
- Gemerkte Einstellungen bleiben erhalten
|
||||
<!-- testen -->
|
||||
- LMB auf Abmelden
|
||||
- Anmeldeseite sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Am Adminbereich anmelden
|
||||
<!-- regeln -->
|
||||
- Ohne Adminrolle erscheint eine Verbotsseite
|
||||
- Berechtigte landen auf der Systemübersicht
|
||||
- Der letzte Benutzername ist vorbelegt
|
||||
<!-- testen -->
|
||||
- Adminanmeldung aufrufen
|
||||
- E-Mail und Passwort eintragen
|
||||
- Bestätigen
|
||||
- Systemübersicht sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Vom Adminbereich abmelden
|
||||
<!-- testen -->
|
||||
- LMB auf Abmelden
|
||||
- Anmeldeseite sichtbar
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Verlauf löschen
|
||||
<!-- ziel -->
|
||||
Entfernt Gespräch, Produktbezüge und Uploads
|
||||
<!-- regeln -->
|
||||
- Während des Empfangs gesperrt
|
||||
- Löscht alle temporären Uploads mit
|
||||
- Keine Rückfrage, keine Wiederherstellung
|
||||
- Danach fehlen alle Bezugsanker
|
||||
<!-- testen -->
|
||||
- LMB auf Verlauf löschen
|
||||
- Verlauf leer
|
||||
- Uploadliste leer
|
||||
----------------------------------------
|
||||
<!-- funktion -->
|
||||
Hilfe öffnen
|
||||
<!-- ziel -->
|
||||
Zeigt das Bedienhandbuch im Chat
|
||||
<!-- regeln -->
|
||||
- Nur bei vorhandener Handbuchdatei
|
||||
- Höchstens 512 KB werden gelesen
|
||||
- Die Hilfe ändert keine Antwortlogik
|
||||
<!-- testen -->
|
||||
- LMB auf Hilfe
|
||||
- Handbuch im Fenster sichtbar
|
||||