ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Lern-App, die aus einem Schlagwort (Pilot: Maschinen- und Anlagenführer) einen Kurs aus amtlichen Quellen erzeugt und aktuell hält.檢視完整 README ↗
A learning app for German vocational training that turns a keyword such as a trade name into a course built from official sources, checks every question with an LLM judge, and publishes only what passes.
Live: content-agent-ashen-nu.vercel.app · sample data without an account: /lernpfad?demo=1
Apprentices preparing for their exams need material that follows the official framework curriculum, and generic AI text invents facts without saying where they come from. This app runs a pipeline of research, plan, generate (Claude) and evaluate (an OpenAI judge), and a content guard blocks publishing when a unit lacks a source with retrieval date or the AI label. The repo builds itself: an agent loop picks Linear issues, opens pull requests and merges them only after lint, tests, build, axe and Lighthouse pass, observed from the separate Leitstand.
Runtime and API details: docs/ARCHITECTURE.md. Pilot course: Maschinen- und Anlagenführer (MAF); a second course for Industriekaufleute is generated by the same pipeline.
git clone https://github.com/siinanXD/Content-Agent-Lernapp && cd Content-Agent-Lernapp
npm ci
npm run dev # http://127.0.0.1:43123, works without keys (in-memory mock store)
content_versions), so a bad run can be rolled back.No open-source license: all rights reserved (owner decision, SIN-752).
Lern-App, die aus einem Schlagwort (Pilot: Maschinen- und Anlagenführer) einen Kurs aus amtlichen Quellen erzeugt und aktuell hält. Die folgenden Abschnitte beschreiben Entwicklung und Betrieb.
| Layer | Choice |
|---|---|
| App | Next.js 16 + React 19 + TypeScript + Tailwind 4 |
| Hosting | Vercel |
| Persistence | Supabase EU (AP-17) with in-memory mock fallback |
| Quality / tracing | Langfuse Cloud EU — JS/TS SDK v5 / platform v4 OTEL (SIN-197) |
| Ops scaffold | Hermes weekly source check + Telegram (AP-10/AP-16) |
| Models | Claude for generate (Batch); OpenAI mini as judge (D-06/D-07) |
docs/ops/SIN-438-grants.md — Tabellenrechte prüfen, transaktionaler Migrationstest und Rückkehrverfahren.
Verbrauch von Bau-/Reparaturläufen wird privat in Linear gespeichert; öffentliche PR-Steckbriefe und Tages-Updates zeigen diese Beträge nicht. Der Wochenleser liest private Kommentare mit Seitenabruf und dedupliziert Laufkennungen; historische PR-Marker bleiben vorübergehend lesbar.
docs/PRODUCT.md — Konzept und Bauplan AP-00–AP-12
docs/DECISIONS.md — Architekturentscheidungen mit Links
docs/ARCHITECTURE.md — Runtime- und API-Überblick
AGENTS.md — Entscheidungs- und Stopp-Regeln
docs/LANDKARTE.md — Repo-Landkarte: wo liegt was, Befehle, Konventionen (SIN-320)
docs/autonomy/groessen.md — Größen der Issues, Modell und Runden je Größe, Bündeln, Verbrauch (SIN-320)
docs/content/README.md — Curriculum-Maps (AP-13): MAF in allen fünf Schwerpunkten und Industriekaufleute 2024
docs/content/DIDAKTIK.md — Didaktik-Vorgabe (AP-18): Schablone je Einheit, Fragestufen, Wiederholung, Prüfungsmodus, Bilder
npm install
npm run dev
Dev server: http://127.0.0.1:43123 (npm run dev → port 43123).
Playable path (Figma approved by Sinan 2026-10-02; Didaktik D-31):
/ Startseite für Bildungsträger (Scroll-Story), /willkommen App-Einstieg/start — Schlagwort + Lernvariante → Kurs erzeugen/lernpfad — Module/Blöcke, Wiederholung, Prüfungsmodus/einheit/unit-03 — sections + alle 5 Fragetypen (+ Bildfragen)/wiederholung — Leitner 1/3/7/14/pruefung — schriftliche Teile aus exam.gradedParts (MAF PT/PP/WiSo)/ergebnis — Punkte + Ampel je Gebiet/profil — Fortschritt, Stapelgröße, PrüfungsreifeBeispielmodus ohne Konto (SIN-408): /lernpfad?demo=1 schaltet für die Browser-Sitzung erfundene Beispieldaten ein (Ergebnis, Wiederholung, Profil, Serie). Es wird nichts gespeichert oder gesendet; ?demo=0 beendet ihn. /quellen zeigt die Quelle je Einheit mit Abrufdatum. Gruppenansicht: /ausbilder?demo=1 (SIN-385). Ausbilder (SIN-415): /ausbilder/zugang?code=… löst den Einladungslink ein, /ausbilder/gruppen zeigt mehrere Gruppen und die Zugänge „x von y vergeben“, /ausbilder/archiv die archivierten Gruppen (Archivieren statt Löschen). Organisation, Kontingent und Einladungslinks legt der Admin unter /admin an (SIN-416): Reiter Organisationen (Zugänge „x von y“, Status, Link erzeugen, neue Organisation), Anfragen (demo_requests) und Alle Kurse. Die Rolle admin steht in app_metadata und wird nur mit dem Service-Role-Key gesetzt (supabase.auth.admin.updateUserById(id, { app_metadata: { role: "admin" } })); der Server prüft sie bei jeder Anfrage.
Design source: Figma · tokens in docs/design/. Phase-A SVGs: npm run content:mermaid.
npm run check:fast # Lint, Typecheck, Unit-Tests ohne Keys (vor jedem Push)
npm test
npm run content:mermaid
npm run test:a11y
npm run test:lighthouse # app must be running on :43123 (or add -- --serve)
npm run hermes:dry-run # AP-10 scaffold (no live Telegram)
npm run pilot:maf # AP-11 seed/fixture pipeline (app on :43123)
npm run supabase:verify # when SUPABASE_* present
npm run build
npm run lint
A11y gates (axe über alle Routen, Tastatur, Lighthouse a11y ≥ 0.9) laufen in den CI-Jobs e2e und perf (.github/workflows/ci.yml, gemeldet über den Sammel-Check build) und dürfen nicht abgeschaltet werden.
Quelle: docs/diagramme/pipeline.mmd, Nutzerwege: docs/diagramme/nutzerwege.mmd. Der Block unten ist eine Kopie von pipeline.mmd (ein Test prüft das). FigJam wird in einer Claude-Sitzung aus den .mmd nachgezogen, das Tages-Update meldet „Diagramme geändert“.
%% Pipeline-Ablauf des Loops, Stand main 09.10. (SIN-376). Quelle für das FigJam-Board „Pipeline-Ablauf“.
%% Ändern sich .github/workflows/ oder scripts/autonomy/, diese Datei im selben PR anpassen.
flowchart TD
subgraph Planung
Radar["Trend-Radar (sonntags)"] --> Planer
Planer["Planer (planner.yml, sonntags; offene Fertig-Liste sperrt Ideen)"] --> Schlange["Linear-Schlange"]
end
Schlange --> Dispatcher["Dispatcher (dispatch.yml): dringend, dann v1, höchstens 1 Idee pro Woche; sofort nach Merge, höchstens 2 parallel"]
Dispatcher --> Worker["Worker (worker.yml, Claude; bei offenen Haken nur daran, derselbe Haken-Stand höchstens 2-mal, sonst needs-human, SIN-795)"]
Worker --> PR["Pull Request mit Steckbrief (Bereiche: Frontend, Backend, Datenbank, Infra, Deploy)"]
PR --> Anstoss["pruefer-anstoss.yml: Anstoß an den Leitstand-Prüfer; merge-gate verlangt Beleg für den Head (SIN-1001)"]
subgraph Prüfung
PR --> CI["CI: Lint, Typecheck, Tests, Build, axe, Layout-Test, Lighthouse, Leistungsbudget"]
PR -- "Frontend geändert" --> Sicht["KI-Sichtprüfung gegen Figma: Kommentar, kein Gate (sichtpruefung.yml, SIN-523)"]
PR -- "Vorschau fertig" --> PRC["PR-Crawler: nur geänderte Seiten, auch eingeloggt, Bild oder Video im PR (pr-crawler.yml, SIN-906, SIN-914)"]
PR -- "Prompt, Richter oder Modell geändert" --> Gold["Goldset-Prüfung: Basis gegen PR, über 3 Prozentpunkte schlechter = rot (goldset.yml, SIN-629)"]
PR --> CodeQL["CodeQL"]
PR --> Review["Review-Agent (zweites Modell)"]
CI --> Gate{"pr-gate: Risiko"}
CodeQL --> Gate
Review --> Gate
end
CI -- rot --> Repair["repair.yml: bis 3 Runden, ohne Commit startet ci neu, Claude-Fehler = sofort needs-human"]
Repair --> CI
Repair -- "nach Runde 3" --> Mensch["needs-human, Stopp"]
Gate -- "risk:high" --> Freigabe["Label freigegeben (Sinan)"]
Freigabe --> Merge
Gate -- "risk:medium (Aufbauphase: ohne Frist)" --> Merge
Gate -- "risk:low" --> Merge["Auto-Merge (Squash)"]
Merge --> Haken{"Alle Fertig-Kriterien belegt? (SIN-779)"}
Haken -- ja --> Done["Linear: Done"]
Haken -- nein --> Offen["Issue bleibt offen, Kommentar nennt offene Haken"]
Merge --> Dispatcher
Merge --> Migr["Migrationen anwenden: additiv automatisch, sonst Sinan-Aufgabe (SIN-374, SIN-451)"]
Merge --> Bruch{"gate-bruch-Erkennung"}
Bruch -- "CI auf main rot" --> Revert["revert-guard: Revert-PR nur wenn Schritt davor grün (SIN-502)"]
Revert -- "Revert-PR gemergt" --> LinearTodo["Linear: Issue auf Todo, 2. Rücknahme needs-human (SIN-492)"]
Migr --> Deploy["production-deploy (höchstens 1× pro Stunde)"]
Deploy --> Smoke["Smoke-Test"]
Smoke -- rot --> Revert
Smoke -- grün --> Live["Live-Check (nach-deploy.yml)"]
Live -. "nachts / montags" .-> Testnutzer["Testnutzer-Agent: Crawler (auch eingeloggt) und 3 Personas, Funde werden Issues (testnutzer.yml, SIN-640, SIN-914)"]
Deploy -- "grün, höchstens 1× pro Tag" --> Video["Tutorial-Video (video.yml): Freigabe nötig (SIN-483)"]
Deploy -- "nur von Hand, freigabe ja" --> Werbeclip["KI-Werbeclip (werbeclip.yml): bis 5 €, Freigabe nötig (SIN-520)"]
Kurs["Kurs veröffentlicht"] -- "von Hand" --> Marketing["Werbetexte (marketing.yml): Prüfung, dann Freigabe nötig (SIN-484)"]
Live --> Waechter["Wächter / Loop-Status (status.yml)"]
Waechter -- "neuer App-Code" --> Deploy
Backup["Sicherung (backup.yml) nachts, Restore-Test (restore-test.yml) monatlich in wegwerfbarer Supabase (SIN-337)"] --> Waechter
Waechter --> Update["Tages-Update (digest.yml, 10:00 und 20:00)"]
Waechter --> Leitstand["Leitstand: Start/Ende jedes Schritts und Schnappschuss in Supabase (SIN-303)"]
Worker -.-> Leitstand
subgraph Projektwaechter["Projekt-Wächter (Leitstand-Repo, waechter.yml, stündlich, alle Projekte In Progress mit GitHub-Link)"]
PW["Projekt-Wächter"] --> PWS["Schlange leer: Backlog rückt nach, sonst Planungs-Issue"]
PW --> PWH["Hänger: über 6 h In Progress ohne PR, nur Label claude: Todo, beim 2. Mal needs-human; Worker 2-mal ohne PR: needs-human; Claude-Sofortabbruch zählt als Limit-Pause; 3 Fehlläufe desselben Auftrags in 60 Min ohne PR: Pause 60 Min (SIN-548)"]
PW --> PWU["Projekt-Update in Linear, einmal am Tag"]
PW --> PWR["Roter PR, 30 Min ohne Commit: @claude, Runde zählt mit"]
end
PWS --> Schlange
PWR --> Repair
subgraph Inhalte
Fabrik["Content-Fabrik (content-grow.yml, alle 2 h solange Content-Punkte der Fertig-Liste offen sind (sonst Mo/Mi/Fr), Cron und Anstoß durch den Dispatcher (Ereignis fabrik-anstoss), jeder Lauf im Statusprotokoll, bei API-Limit pausiert und sinan-Issue, am Ende Kostenbericht)"] --> Bewertung["Bewertungslauf"]
Bewertung --> Update
Bewertung --> Freigabe["Kurs veröffentlichen (content-publish.yml, von Hand, Prüfung vor published, danach Live-Check)"]
end
| Was | Befehl / Workflow | Wirkung |
|---|---|---|
| Leistungsbudget | npm run build && npm run perf:budget -- --serve · Grenzen in performance-budget.json | LCP (höchstens 2,5 s), CLS, TBT und JS-Größe je Route (Handy, Median aus 5 Läufen; --details zeigt das LCP-Element, --shard 1/2 misst nur einen Teil der Routen; CI nutzt zwei Teile parallel). Überschreitung macht build rot und blockiert den Merge. |
| API-Tests (SIN-538) | npm run build && npm run api:test -- --serve | Newman führt docs/api/postman-collection.json gegen die App aus (Health, Pipeline-Kette, 400/404); jede Prüfung zu Status und Antwortform muss grün sein. |
| Bildvergleich | npm run visual -- --update-snapshots, danach npm run visual · Workflow visual.yml | Handy- und Desktop-Bilder aller Seiten gegen main. Nur Hinweis (Lauf-Bericht, Artefakt bildvergleich), kein Gate; die Referenz kommt immer frisch aus main. Läuft nur, wenn der PR src/app, src/components oder Styles ändert, sonst grün (SIN-648). |
| Layout-Test (Gate, SIN-523) | npx playwright test e2e/layout.spec.ts · läuft im CI-Job e2e (Teil von build) | Alle Seiten aus e2e/routes.ts auf Handy (390×844) und Desktop (1280×800): keine überlappenden Knöpfe oder Textblöcke, kein waagerechtes Scrollen, kein abgeschnittener Text, Klickziele ≥ 44 px, nichts außerhalb des Bildes oder hinter fixen Leisten. Fehler nennen Seite, Ansicht und beide Elemente; das Artefakt playwright-results enthält das Bild mit roten Kästen. Gewollte Überlagerung: data-layout-ok="Begründung" am Element. |
| Goldset-Prüfung (SIN-629) | Workflow goldset.yml · lokal npm run quality:regression -- messen --out m.json · braucht OPENAI_API_KEY | Bei PRs, die Generator-Prompt, Richter oder Modellwahl ändern, misst der Job Richter (Erstquote auf 30 festen Einträgen, Urteil wie erwartet auf 70) und feste Prüfsätze (Quelle passt zum Beruf, keine Prüfhinweise, Elektro-Hinweis) mit dem Stand von main und dem PR. Über 3 Prozentpunkte schlechter oder Prüfsatz verletzt = rot, Ergebnis als PR-Kommentar. Wenige Cent je Lauf (Deckel 2 €), Ledger goldset-regression, Trace in Langfuse. |
| Testnutzer-Agent (SIN-640) | Workflow (Crawler nachts, Personas montags, auch von Hand mit , , ) · |
Ops / pilot docs: docs/ops/HERMES.md · docs/pilot/MAF-PILOT.md · docs/learning/LOOP.md · docs/ops/SUPABASE.md.
First live course slice after the curriculum map: modules M0, LF1, LF2, PA (~280 units), generate with Claude Batch, judge with OpenAI mini, publish only through the quality gate. Tracked in SIN-193. Costs and scores should land in Langfuse Cloud EU — prefer completing the v4 cutover (SIN-197) before relying on dashboards for that run.
npm run ap15:phase-a:dry
npm run ap15:phase-a
Artifacts land in docs/ops/AP15-PHASE-A.md and docs/ops/ap15-runs/.
Vercel project pointed at this repo. Empty/scaffold build must succeed (AP-01).
Git deploys are off (git.deploymentEnabled: false in vercel.json, SIN-309): neither main nor PR branches create Vercel deployments, so nothing counts against the Hobby limit of 100/day. Production is deployed by the production-deploy workflow (vercel deploy --prod via CLI, SIN-332; needs secret VERCEL_TOKEN and variable VERCEL_PROJECT_ID, plus VERCEL_TEAM_ID for team accounts). The status workflow starts it: at most once per hour, only when app code changed, and only one attempt per commit (a CANCELED/ERROR attempt is reported as "Production hängt" instead of being retried). If Production cannot be read from Vercel, or is more than 3 h behind main, the Loop-Status shows a red item under "Braucht dich" and sends Telegram (TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, optional). The deploy hook from SIN-266 is retired (secret VERCEL_DEPLOY_HOOK_PROD is no longer used).
Functions run in Frankfurt (regions: ["fra1"] in vercel.json). Right after each Production deploy the same production-deploy run checks /api/health and /api/learner/phase-a for 200 and opens a revert PR otherwise (SIN-308). URL env vars (e.g. LANGFUSE_BASE_URL) are cleaned of quotes and validated in src/lib/env.ts; an invalid value disables the feature and logs a warning instead of crashing.
Live-Check (SIN-319). After each Production deploy (and nightly at 21:05 Berlin time) the workflow nach-deploy checks the live app against docs/ops/live-checkliste.md: API routes (scripts/autonomy/live-check.mjs), all pages on phone and desktop, the unit flow with all 5 question types, exam mode, offline mode, service worker, axe and a Lighthouse short run (live/live.spec.ts). It only reads or uses test data (write endpoints are stubbed, test id livecheck-<time>). Result: artifact live-check (checklist + screenshots) and the line "Live-Check hh:mm: n/n grün" on the status page and in the daily update. If it is red after a deploy, revert-guard opens a revert PR. Every new page or feature goes into the checklist (a unit test keeps list and checks in sync). Locally: npm run build && npm start -- --port 43123, then npm run live:local. Against another URL: PLAYWRIGHT_BASE_URL=<url> npm run live:browser and npm run live:api -- --base <url>, or run the workflow by hand with a URL.
Tutorial-Video (SIN-483). Der Workflow video nimmt den Klickweg Start → Beruf wählen → Lernpfad → erste Einheit → Ergebnis gegen die Production-URL auf (video/aufnahme.spec.ts, playwright.video.config.ts), schneidet ihn mit Revideo (video/schnitt/, 1920×1080: Titel, Handy-Aufnahme 390×844 im Rahmen links, Schritt-Titel und Text in der rechten Spalte, nie über der App, Logo, Hinweis „Lerninhalte mit KI erstellt“, Farben aus docs/design/tokens.json) und legt das MP4 in Supabase Storage (Bucket werbemittel) und als Zeile in werbemittel ab, Status wartet_auf_freigabe. Kein KI-Videomodell, 0 € API, Länge unter 90 Sekunden (sonst Fehler), ohne Ton. Auslöser: von Hand oder nach erfolgreichem production-deploy, höchstens 1 Lauf pro Tag. Schreibende Endpunkte sind abgefangen, es gibt keine Personendaten. Je Schritt entsteht ein Standbild aus dem fertigen MP4 (Artefakt video-standbilder, SIN-522). Hilfen: scripts/autonomy/video.mjs. Ohne SUPABASE_URL/SUPABASE_SERVICE_ROLE_KEY bleibt das Video ein Artefakt (tutorial-video).
KI-Werbeclips (SIN-485). node scripts/autonomy/werbeclip.mjs plan zeigt als Trockenlauf geplante Clips (3 Entwürfe, 1 Final) und Kostenschätzung ohne API-Aufruf. lauf (Workflow werbeclip, nur von Hand mit Eingabe freigabe: ja, Secrets HIGGSFIELD_KEY_ID und HIGGSFIELD_KEY_SECRET) erzeugt die Clips über die Higgsfield-API, fragt den Status ab (Backoff; failed/nsfw werden gemeldet), lädt das Ergebnis herunter, blendet „Mit KI erstellt“ ein (Revideo, video/schnitt/) und legt es in Storage ab. Vor jedem Aufruf wird der Deckel von 5 € pro Produkt geprüft; Modelle, Preise und Endpunkte stehen in docs/autonomy/higgsfield.json. Ergebnis: Zeile in werbemittel mit Kosten, KI-Kennzeichnung und Status wartet_auf_freigabe.
Werbetexte (SIN-484). Der Workflow marketing (von Hand, Eingabe Kurs-Stichwort, z. B. MAF) liest die Zahlen eines veröffentlichten Kurses aus der Datenbank (Einheiten, Minuten, Quellen, Fragen) und schreibt 3 Varianten: LinkedIn-Beitrag, Kurztext für die Website, E-Mail an Bildungsträger. Zielgruppe sind Bildungsträger und Ausbilder (FernUSG). Modell: claude-haiku-5-5, bei verworfenem Text einmal claude-sonnet-5-5, Deckel 1 € pro Lauf. scripts/autonomy/marketing.mjs prüft jeden Text: Hinweis „mit KI erstellt“ nötig, keine Garantien, keine IHK-Aufgaben oder -Logos, keine Zahl außerhalb der Datenbank. Durchgefallene Texte werden verworfen; bestehen nicht alle 3, wird nichts gespeichert. Ablage in werbemittel (Status wartet_auf_freigabe), veröffentlicht wird nie automatisch. Braucht ANTHROPIC_API_KEY, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY.
Set in Vercel / local .env.local (never commit): Anthropic, OpenAI, Langfuse (EU), Supabase (EU). Work without keys uses mocks.
Abo im Testmodus (SIN-771): /abo startet Stripe Checkout (Abo-Modus), /abo/bestaetigung zeigt den Stand. Braucht STRIPE_SECRET_KEY (sk_test_…) und STRIPE_PRICE_ID (Test-Preis); Live-Schlüssel lehnt src/lib/abo/abo.ts ab. Ohne beide zeigt /abo „noch nicht eingerichtet“.
Langfuse quality-gate tracing uses JS/TS SDK v5 / platform v4 OTEL ingestion (docs/quality/README.md). Course runs appear as one Langfuse session with one trace per unit (M3 · 02 Spannmittel), containing the generation and every judged question with answer, reason and scores (SIN-299, SIN-383); npm run langfuse:setup creates score configs, the safety-sample annotation queue, prompts and the dashboard (docs/ops/langfuse-dashboard.md).
supabase/migrations/ (additive SQL + RLS). Runbook: docs/ops/SUPABASE.md.scripts/verify-table-grants.sql im SQL-Editor oder per psql; meldet „ok“ oder nennt offene Rechte für anon und authenticated.SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY: API routes persist via Supabase (service role, server-only).COURSE_STORAGE=mock): in-memory mock-store — tests stay green.npm run supabase:verify.NEXT_PUBLIC_SENTRY_DSN, DSN-Host ingest.de.sentry.io) erfasst Fehler der App-Routen und der Pipeline (scripts/content-grow.ts). Ohne Personendaten (src/lib/sentry-privacy.ts); ohne DSN passiert nichts.SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT); ohne Token steht „nicht verfügbar“.docs/decisions/SIN-406-fabrik-durchsatz.md). Deckel und Qualitäts-Schwelle sind unverändert.STRUCTURED_OUTPUTS entfällt; Generierung, Richter, Plan- und Research-Agent nutzen ein Schema, docs/decisions/SIN-1036-structured-json.md). Eine Richter-Antwort, die das Schema verletzt, macht die Einheit „nicht bestanden“ mit Grund. Abgelehnte Batch-Anfragen stehen mit API-Fehlertext im Log und Bericht; 0 Einheiten oder über 50 % gescheiterte Teilaufträge machen content-grow und ap22-ab rot (Exit 1).nichtVersucht mit Grund (Kostendeckel, Zeitlimit, begonnene Module, andere Map). Die Kosten je Einheit rechnen ohne Reparatur, damit der Deckel nicht doppelt zählt (SIN-434, docs/decisions/SIN-434-fabrik-engpass.md).docs/decisions/SIN-431-indkfl-fabrik.md). Jeder Lauf bedient eine Map und wechselt zum nächsten Lauf; Kurs und amtliche Quellen für Industriekaufleute legt die Migration 20261012010000 an.MAP_COURSES, erzeugt werden sie erst mit CONTENT_GROW_SCHWERPUNKTE=1 und nach Metall und Industriekaufleuten. Gemeinsame Module erzeugt nur MAF Metall. Der Trockenlauf (npm run content:grow -- --dry-run) nennt je Map Ziel, vorhanden, geteilt, neu (SIN-479, docs/decisions/SIN-479-schwerpunkte.md).content-publish.yml, nur von Hand, Eingabe Kurs-Stichwort). Standard ist der Trockenlauf; er zeigt die Prüfungen (Quelle und Abrufdatum, Richter bestanden, Verbotsliste), schreibt nichts. Mit dry_run aus setzt er bei null Mängeln courses.status = published, schreibt das Ereignis publish und startet den Live-Check. Lokal: ().https://github.com/siinanXD/Content-Agent-Lernapp
Jeder PR wird automatisch geprüft (build, pr-title, merge-gate). In der Aufbauphase (SIN-855) mergen risk:low und risk:medium ohne Frist nach grünen Checks. Danach gilt: risk:low mergt ohne Frist, risk:medium (Workflow-Rechte, Gate-Änderungen) nach 30 Min Einspruchsfrist (Label einspruch:30m, Stopp mit no-automerge), risk:high wartet auf das Label freigegeben. Nach jedem Merge startet post-merge den Dispatcher sofort. Details: AGENTS.md, Abschnitt „Pull Requests und Merge“. Hat Cursor kein Guthaben, übernimmt Claude: @claude in einem Issue-Kommentar.
docs/content/MAF-CURRICULUM.md — Vorgängerversion v1 (nur Metall); runtime loader uses docs/content/maf-metall.json via AP-14 (PR #24)
testnutzer.ymlebeneurldry_runLIVE_URL=<url> node scripts/autonomy/crawler.mjsDer Crawler (ohne KI) geht alle Routen auf Handy und Desktop ab und prüft Fehler, tote Links, Seitwärts-Scrollen, LCP unter 2,5 s und axe. Die Personas (Azubi Metall, Azubi vor der Zwischenprüfung, Ausbilder) spielen feste Wege; claude-haiku-5-5 bewertet Bilder und Texte nach fester Liste (Deckel 0,50 USD). Funde werden Korrektur-Issues (Label frontend/content, Dubletten-Prüfung, höchstens 5 je Lauf), der Bericht ein Kommentar in SIN-640. Nur lesend, schreibende API-Aufrufe sind abgefangen. Braucht LINEAR_API_KEY, Personas ANTHROPIC_API_KEY. Eingeloggt (SIN-914): Testkonten agent-lernend, agent-ausbilder (Repo-Variablen AGENT_LERNEND_EMAIL, AGENT_AUSBILDER_EMAIL, optional AGENT_ORGANISATION_ID), Sitzung per scripts/agent-testnutzer/sitzung.mjs ohne Passwort, auch im PR-Crawler; Testdaten (agent-test-…) zählen nicht in Kennzahlen. Entscheidung: SIN-640, SIN-914. |
| PR-Crawler (SIN-906) | Workflow pr-crawler.yml (nach der Vercel-Vorschau, auch von Hand mit pr, url) · node scripts/pr-crawler/routen.mjs --dateien <liste> --quelle <checkout> | Leitet aus den geänderten Dateien des PRs die Seiten ab (Seite, Komponente, lib-Datei über Importe; höchstens 6) und prüft nur diese auf der Vorschau wie der Testnutzer (Fehler, tote Links, axe, Knöpfe, erste Frage). Beleg im PR-Kommentar <!-- pr-crawler -->: Bild je Route (Handy, Desktop), ab 2 Seiten ein Video (WebM, höchstens 10 MB, im Artefakt). Hat das verknüpfte Linear-Issue ein Planungsbild (Anhang oder Bild in der Beschreibung, LINEAR_API_KEY), steht es als Soll neben dem Ist-Bild (SIN-1008); ohne Bild nichts. Fund = roter Check, Grund in loop_events (Schritt pr-crawler); ohne Frontend-Änderung „Übersprungen“ mit Grund. Braucht VERCEL_AUTOMATION_BYPASS_SECRET, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY. Entscheidung: SIN-906. |
| KI-Sichtprüfung (Hinweis, SIN-523) | Workflow sichtpruefung.yml · node scripts/autonomy/figma.mjs --bild "02 Lernpfad" | Bei PRs an src/app oder src/components bekommt claude-haiku-5-5 Bilder der betroffenen Seiten (Handy, Desktop) und das Figma-Frame und schreibt einen Kommentar mit höchstens 5 Punkten und den Kosten. Blockiert nichts. Braucht ANTHROPIC_API_KEY, optional FIGMA_ACCESS_TOKEN. |
| Aufräum-Agent | npm run cleanup:scan · Workflow aufraeumen.yml (montags) | Ungenutzte Dateien, tote Pakete, große Dateien, Doppelungen, Doku-Abgleich: ein PR pro Woche. |
| Trend-Radar | Workflow trend-radar.yml (sonntags) · node scripts/autonomy/trend-radar.mjs --week | Claude recherchiert Trends (GitHub, Figma Riffs/Weave, Hugging Face, Changelogs, Skills/MCP), schreibt docs/research/trend-radar-<JJJJ-KW>.md (ein PR pro Woche) und legt pro Lauf genau ein Linear-Issue „Trend-Radar KW “ (Label research, alle Funde als Checkliste) an; bei dry_run entsteht nichts in Linear. Nichts wird automatisch eingebaut. Der Tages-Update nennt den Bericht montags. Entscheidung: SIN-313. |
| README-Erinnerung | npm run readme:check · Schritt im CI-Job pruefen (Teil von build) | Warnung, wenn ein PR Befehle, Seiten, Umgebungsvariablen oder Workflows ändert, ohne README.md anzufassen. |
| Changelog | npm run changelog (braucht volle Git-Historie) | CHANGELOG.md aus den Conventional-Commit-Titeln auf main, ohne KI. Erzeugt, nicht von Hand bearbeiten; der Aufräum-Lauf aktualisiert sie. |
| CodeQL | Workflow codeql.yml (PR, main, montags) · node scripts/autonomy/codeql-gate.mjs <Ordner> | JavaScript/TypeScript. Funde ab security-severity 7.0 machen den Lauf rot (SARIF als Artefakt codeql-sarif). |
| Paket-Updates | .github/dependabot.yml (Dependabot, montags) | npm und Actions: Minor/Patch als Bündel, Major einzeln. Sicherheits-Updates sofort (Repo-Einstellung). Entscheidung: SIN-295. |
| Review-Agent | Workflow review.yml · node scripts/autonomy/review.mjs --pr <Nr> · Secret OPENAI_API_KEY, Repo-Variable REVIEW_DAILY_CAP_USD (Standard 2) | Ein OpenAI-Modell liest jeden PR-Diff gegen den Auftrag und kommentiert mit Schwere. Schwer: Claude repariert im selben PR (zählt als Runde), leicht: nur Hinweis. Behauptet ein Fund rote Tests oder einen kaputten Build, obwohl build grün ist, gilt er als widerlegt; von der Reparatur begründet verworfene Funde („Fund geprüft, keine Änderung nötig“) zählen nicht als Runde und kommen nicht erneut als schwer (SIN-381). Kosten je Review im Kommentar, Tagesdeckel, Label no-review überspringt. Entscheidung: SIN-297. |
| Recht-und-Inhalt-Wächter | src/lib/review/ · läuft in POST /api/courses/{id}/publish | Blockiert die Veröffentlichung (422, reason: content_guard) bei fehlender Quelle oder Abrufdatum, fehlender KI-Kennzeichnung, Personendaten oder IHK-Aufgaben als Vorlage. Die Verbote aus AGENTS.md stehen als Liste in regeln.ts. |
| Fertig-Liste einsortieren (SIN-528) | node scripts/autonomy/einsortieren.mjs --projekt <Linear-Projekt> [--fertig docs/FERTIG.md] [--tabelle out.md] [--apply] · braucht LINEAR_API_KEY | Einmalig: offene Issues nach „v1 Grundgerüst“ oder „v2 Ideen“ (+ Label idee). Ohne --apply nur die Tabelle. Danach startet der Dispatcher dringend → v1 → höchstens eine Idee pro Woche; loop_snapshot bekommt fertig_v1, gesamt_v1, ideen_offen. Entscheidung: SIN-528. |
| Leitstand-Ereignisse | node scripts/autonomy/leitstand.mjs ereignis --schritt <dispatch|worker|pr-gate|planner|digest|status> --status <start|ok|fehler> · braucht SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY (vorhandene Secrets) | Jeder Schritt schreibt Start und Ende in Supabase loop_events (Projekt, Schritt, Issue, PR, Status, Dauer; der Worker zusätzlich Tokens und total_cost_usd), status.yml den Stand in loop_snapshot (Kontingente, Schlange, offene PRs). Lesen nur für Nutzer in leitstand_nutzer (RLS), keine Personendaten. Ohne Secrets nur eine Warnung. Für alle Repos gleich (LEITSTAND_PROJEKT überschreibt den Projektnamen). Entscheidung: SIN-303. |
| Aufgaben für Sinan | node scripts/autonomy/sinan.mjs sync|list|create (braucht LINEAR_API_KEY) | Was nur Sinan tun kann, steht als Linear-Issue mit Label sinan (Link, Minuten, Schritte, Prüfung), nicht im PR-Text. Tages-Update und Status-Seite zeigen sie unter „Braucht dich“; der Loop schließt sie selbst, wo er es lesen kann. Entscheidung: SIN-310. |
| Projekt-Starter (nur Plan) | node scripts/autonomy/starter.mjs plan --name N --idee I [--supabase geteilt|eigen|aus] [--ohne posthog,langfuse] [--json] · starter.mjs sql --schema S | Baut aus Name und Idee den Plan für ein neues Projekt (Schritte je Dienst, benötigte Konto-Tokens nur als Namen, Prüfung je Schritt, Start-Issues). Führt nichts aus; --live ist gesperrt, bis die Konto-Tokens in Infisical liegen und der Loop eine Woche stabil lief. Entscheidung: SIN-202. |
Tagesdeckel judge-backfill (SIN-894) | Workflow run-task.yml, Eingaben task=judge-backfill, optional kurs (z. B. Industriemechaniker) · Repo-Variable TAGESDECKEL_EUR (Standard 40) | Der Deckel zählt Euro des Tages aus judge_runs.cost_eur, nicht Läufe. Summe < Deckel: weiterer Lauf startet; Summe ≥ Deckel: Stopp, Grund als loop_events-Schritt tagesdeckel. Deckel je Lauf (19 €) bleibt. kurs bewertet nur diesen Kurs, leer = alle. Entscheidung: SIN-894. |
| Modellvergleich (SIN-437) | Aufgabe ab-alle-modelle in run-task (Workflow run-task.yml) · lokal npm run ap22:alle:dry (kostenlos: Kandidaten und Kostenschätzung), npm run ap22:alle · braucht ANTHROPIC_API_KEY, OPENAI_API_KEY | Haiku 5.5, Sonnet 5.5, gpt-6-luna, gpt-6.1-sol und chat-latest gegen dieselben 20 LF3-Einheiten (gleicher Prompt, normale Aufrufe, ein Reparatur-Durchgang). Zwei Richter (gpt-5.4-mini und Claude Haiku 5.5): eine Frage besteht nur mit beiden. Bericht docs/quality/runs/ab-alle-modelle-<Datum>.md mit Richter-Schnitten, Abweichungen, Kosten je Einheit (USD, EUR) und je 2 Beispielen im Volltext. Deckel 6 €, Abbruch bei Überschreitung. Wechselt kein Standardmodell. Entscheidung: SIN-437. |
| Prüfhinweise bereinigen (SIN-620) | npm run content:bereinigen [-- --apply] · COURSE_STORAGE=supabase, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY | Entfernt Sätze mit internen Prüfhinweisen (stichprobe, gegenzuprüfen, abgleich mit, Quelle: KMK) aus Einheiten und Fragen und ergänzt bei „spannungsfrei“, „verdrahten“, „anklemmen“ den Elektrofachkraft-Satz. Ohne --apply nur Bericht; Antworttexte meldet er als manuell. Danach npm run quality:judge-backfill. Der Wächter vor publish blockiert neue Treffer. Entscheidung: SIN-620. |
| Inhalte zurücksetzen (SIN-632) | npm run inhalte:zuruecksetzen -- liste --kurs <uuid> --einheit <id> · -- --lauf <run_id> [--apply] · -- --kurs <uuid> --einheit <id> --ab <Version> [--apply] · SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY | Jede Änderung an units/questions steht per Trigger in content_versions (alter und neuer Stand, Grund, Issue, Lauf). Das Skript kehrt Versionen eines Laufs oder einer Einheit um; ohne --apply nur Plan. Ablauf bei falschem Inhalt: docs/ops/NOTFALL.md. |
| Bestehensquote des Richters (SIN-507) | npm run quality:quote [-- --out docs/quality/SIN-507-quote.md] · braucht SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY (nur lesend) | Quote über vorhandene Fragen, je Frage die neueste Bewertung (beide Frage-ID-Schreibweisen vereint), aufgeschlüsselt nach Modul, Fragetyp, prompt_version, judge_model, Datum; Durchfaller nach Kriterium, Top 10 Begründungen. Keine API-Kosten. Bericht: SIN-507. |
| Goldset Industriekaufleute (SIN-447, SIN-449) | Aufgabe goldset-indkfl in run-task · lokal npm run quality:goldset-indkfl · braucht OPENAI_API_KEY, für den Datensatz LANGFUSE_* | 35 von Sinan geprüfte Fragen (docs/quality/indkfl-goldset.json, davon 3 Gegenproben). Legt den Langfuse-Datensatz indkfl-goldset an und lässt den Richter alle Fragen bewerten. Bericht docs/quality/runs/indkfl-goldset-check-<Datum>.md: Urteil wie erwartet, Gegenproben erkannt, abgelehnte gute Fragen. Kosten wenige Cent (09.10.: 0,015 $), darum ohne Tagesdeckel; nach jeder Änderung am Richter neu starten (SIN-456). |
node --import tsx scripts/content-publish.ts --keyword <Stichwort> --dry-rundocs/decisions/SIN-796-veroeffentlichen-workflow.mddocs/decisions/SIN-628-staging.md): Neue Einheiten der Fabrik tragen den Status entwurf, geprueft oder veroeffentlicht. Die App zeigt nur veroeffentlicht; Einheiten ohne Status (Bestand) gelten als veröffentlicht. Freigabe automatisch, wenn der Richter bestanden hat und die Proben grün sind, sonst bleibt die Einheit unsichtbar.docs/FERTIG.md offene Content-Punkte hat; leeres API-Guthaben pausiert sie bis zum manuellen Start und legt ein sinan-Issue an (SIN-797, docs/decisions/SIN-797-fabrik-durchlauf.md). Danach gilt wieder: Montag, Mittwoch und Freitag, höchstens einmal je Tag und unter 40 € je 7 Tage (ein Lauf startet nur, wenn sein Deckel von 20 € noch hineinpasst; SIN-645); MAF-Metall-Module ohne Einheiten (LF3 bis LF6) kommen zuerst (SIN-469, docs/decisions/SIN-469-fabrik-laeufe-pro-woche.md).content_factory_runs (Migrationen 20261007020000, 20261010010000), mit Start, Ende und Ergebnis. Auch ein Abbruch (fehlende Secrets, fehlender Kurs, Absturz) hinterlässt eine Zeile mit stop_reason. Der Planer leitet daraus „läuft wöchentlich“ und „hängt“ (2 Läufe ohne neues Modul) ab (scripts/autonomy/fabrik.mjs).stop_reason „fertig: alle Einheiten erzeugt“ (0 €); der Dispatcher-Anstoß ruht danach. Repariert wird eine Einheit höchstens 2 Runden. Kennzahl content_fabrik_kosten zeigt Kosten heute, 7 Tage und Einheiten je € (docs/decisions/SIN-901-fabrik-endet.md).stop_reason „pausiert: API-Limit am “; content_fabrik_status zeigt „pausiert“ statt „hängt“, der Planer legt kein Issue an, der nächste Lauf startet normal (docs/decisions/SIN-450-fabrik-pausiert-bei-api-limit.md).fabrik-haengt.