[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CVKNEPEY1WA7E5FWQ85NJW":3,"skill-same:01M6CVKNEPEY1WA7E5FWQ85NJW":64},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":30,"linkOnly":31,"markdownContent":32,"markdownBody":33,"frontMatter":34,"refName":36,"commitSha":37,"skillDirectory":38,"forksCount":39,"repositoryHtmlUrl":40,"repositoryHomepageUrl":6,"ownerHtmlUrl":41,"ownerBlogUrl":42,"ownerDescription":6,"updatedAt":43,"install":44,"resources":57},"01M6CVKNEPEY1WA7E5FWQ85NJW","repograde",null,"Grade student repositories with optional date filtering in single-repo or bulk mode. Use when the user says \"repograde\", \"grade the repos\", \"grade this repo since \u003Cdate>\", \"bewerte die Abgaben\", \"korrigiere die Repos\", or asks for a repo grading run over a class folder or a single student repository. Do not use for project grading with issues and PRs (use projectgrade) or for knowledge-check exams (use knowledge-assessment).","georgernstgraf\u002Fopencode-helpers","georgernstgraf","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F115418377?v=4","01M6CVHJ34JS0CF98EFFN0FZ76","Georg Graf SPG","01M6CVHJ7VV5VK6RXY62SR0NE2",1,"MIT","https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Frepograde\u002FSKILL.md",[],[5,19,20,21,22,23,24,25,26,27,28,29],"repo","execution","filtering","opencode","education","bulk","mode","student","single","repositories","with","2026-11-10 10:12:30",false,"---\nname: repograde\ndescription: Grade student repositories with optional date filtering in single-repo or bulk mode. Use when the user says \"repograde\", \"grade the repos\", \"grade this repo since \u003Cdate>\", \"bewerte die Abgaben\", \"korrigiere die Repos\", or asks for a repo grading run over a class folder or a single student repository. Do not use for project grading with issues and PRs (use projectgrade) or for knowledge-check exams (use knowledge-assessment).\nlicense: MIT\ncompatibility: opencode\nmetadata:\n  category: education\n  scope: execution\n---\n\n# Repograde Skill\n\n## Purpose\n\nThis skill is the canonical workflow for grading student Git repositories.\nIt handles both full-history grading and date-filtered grading (commits\nfrom a specified cutoff date onwards) in a single unified workflow.\n\n## Output Language: MANDATORY GERMAN\n\nFollow the `grading-shared` **Output Language** rule: natural German with proper\nUTF-8 umlauts (ä, ö, ü, ß), never English.\n\n## Dependencies\n\nThis skill relies on `grading-shared` for: Anrede-Gate (`anrede.txt`), email\nformulas, second-person address rules, database lookup, email JSON structure,\nname parsing from repository basename (CRITICAL: last word = first name,\neverything before it = last name), repository analysis protocol, assignment\ndiscovery protocol (Aufgaben-Discovery), bulk grading concurrency, German\u002FUTF-8\nconstraints, JSON escaping rules, email body format, praise guidelines,\nNoten-TSV and reporting protocol.\n\nDerive output filenames from the repository basename, while using the provided\nrepository path verbatim to locate the repository.\n\n## Consistency Goal (CRITICAL)\n\nThe grading output of this skill MUST be highly standardized across repositories\nand across subagents. Do NOT improvise the structure, heading names, section\norder, or overall depth.\n\nEvery `*_grading.md` file generated by this skill MUST:\n\n1. use the exact section order defined in [REPORT-FORMAT.md](.\u002FREPORT-FORMAT.md),\n2. include all mandatory numeric facts when evidence exists,\n3. explicitly say when evidence is missing or unclear instead of silently\n   omitting a section,\n4. stay within the requested level of detail rather than expanding into a\n   free-form essay.\n\nEvery `*_email.json` body generated by this skill MUST:\n\n1. follow the exact paragraph order defined by `grading-shared` for assignment\n   grading emails,\n2. summarize the same core facts as the grading report,\n3. keep a consistent scope and length across students.\n\n## Execution Context\n\nThis skill operates from a local folder (current working directory), NOT from\nwithin a Git repository. Calling this skill from inside a Git repository is\nan error.\n\nThe CWD contains student Git repositories as subdirectories. These may be\nstructured as `STUDENT_DIR\u002FINNER_PROJECT\u002F.git` (two levels deep). The CWD may\nalso contain name-based symlinks (e.g., `Lastname Firstname -> STUDENT_ID`)\nthat provide the student's real name. A BROKEN name-symlink (target does not\nexist) means the student has not yet submitted their repository URL — see\n`grading-shared` Broken Name-Symlinks (Missing Repository).\n\nFollow `grading-shared` Repository Structure Discovery (Inner Git Repository\nDiscovery) before running any git commands. Use `grading-shared` Student Name\nResolution via Symlinks to determine the student's name.\n\nThe CWD may also contain a `_class` symlink pointing to the corresponding class\nfolder in the teaching repository (e.g., `_class -> \u002Fhome\u002Fgeorg\u002Frepos\u002FGRG-SWP\u002F2ahwii\u002F`).\nThis symlink provides access to assignments and lesson materials.\n\n## Zielordner im `-T`-Repo (CRITICAL)\n\nAlle Ausgaben dieses Skills werden im **privaten `-T`-Repo** abgelegt, niemals\nim Arbeitsverzeichnis mit den Schüler-Repos und niemals im öffentlichen\nTeaching-Repo.\n\nDer normale Arbeitsplatz ist `~\u002Fgits\u002F\u003Ckohorte>-\u003Cfach>\u002F` (z. B.\n`~\u002Fgits\u002F3aaif-wmc\u002F`): **kein** Git-Repo, darin die Namens-Symlinks auf die\nSchüler-Repos und der `_class`-Symlink ins öffentliche Klassen-Repo:\n\n```\n~\u002Fgits\u002F3aaif-wmc\u002F_class -> \u002Fhome\u002Fgeorg\u002Fr\u002FGRG-WMC\u002F3aaif\n~\u002Fgits\u002F3aaif-wmc\u002FAbazi Hamza -> Hamza473A\n```\n\nAuflösung (in dieser Reihenfolge):\n\n1. **CWD liegt bereits in einem `-T`-Repo:** `git rev-parse --show-toplevel`\n   liefert einen Pfad, dessen Basename auf `-T` endet → das ist die Wurzel.\n2. **Sonst über `_class`:** `readlink -f` auf `_class` (immer auflösen — `~\u002Fr`\n   ist selbst ein Symlink auf `repos\u002Fgeorgernstgraf\u002F`); das Ziel hat die Form\n   `\u002F…\u002FGRG-\u003CFACH>\u002F\u003Ckohorte>` → `-T`-Wurzel ist das Schwesterverzeichnis\n   `\u002F…\u002FGRG-\u003CFACH>-T`, die Kohorte ist der Basename des Ziels.\n3. **Sonst:** STOPP und den User fragen (kein Raten).\n\nZielordner: `\u003CT-Wurzel>\u002F\u003Ckohorte>\u002F\u003CYYYY-MM-DD>_\u003Cslug>\u002F`\n(z. B. `~\u002Fr\u002FGRG-WMC-T\u002F3aaif\u002F2026-11-08_repokontrolle\u002F`)\n\n- `\u003CYYYY-MM-DD>` = heutiges Datum des Laufs.\n- `\u003Cslug>` = kurzer Lauf-Bezeichner (z. B. `repos`, `repokontrolle`); aus dem\n  User-Auftrag ableiten, sonst `repograde`.\n- Ordner **bei Bedarf anlegen** (`mkdir -p`) — ein neuer Semester-\u002FLauf-Ordner\n  ist der Normalfall, kein Fehler.\n\nVor dem ersten Schreibzugriff läuft ein **Probelauf (read-only)**: der\naufgelöste `-T`-Ordner, der Zielordner und die geplante Dateiliste werden\nangezeigt; es wird nichts angelegt und nichts geschrieben. Erst danach wird\ngearbeitet.\n\nDie Schüler-Repos bleiben im CWD und werden nur gelesen. `roster.tsv` ist eine\nZwischendatei und landet unter `\u002Ftmp\u002Fopencode\u002F` (nicht im Lauf-Ordner, nicht im\nCommit). Committet wird am Ende im `-T`-Repo (siehe Commit-Protokoll).\n\n## Input\n\nArguments are inferred from the user's request. Parse the user message to\ndetermine the mode:\n\n| User provides | Mode |\n|---------------|------|\n| Nothing (just \"grade\" or similar) | Bulk mode, all commits |\n| Repository path only | Single-repo, all commits |\n| Date only (ISO format YYYY-MM-DD) | Bulk mode, filtered commits |\n| Date + repository path | Single-repo, filtered commits |\n\n### Date Validation\n\nIf a date argument is detected, it MUST strictly follow ISO 8601:\n\n```\nYYYY-MM-DD\n```\n\nValid: `2025-03-15`, `2024-12-01`\nInvalid: `2025-3-15`, `15-03-2025`, `2025\u002F03\u002F15`, `2025-03`\n\nIf the date is invalid, STOP IMMEDIATELY with error:\n\"Invalid date format: '[input]'. Expected ISO date format: YYYY-MM-DD (e.g., 2025-03-15)\"\n\n### Date Filtering Logic\n\nWhen a date is provided:\n1. Parse the cutoff date as `YYYY-MM-DDT00:00:00` (midnight at start of day).\n2. Only inspect commits where `commit_date >= cutoff_date`.\n3. Use `git log --after=\"YYYY-MM-DD\"` to filter commits.\n4. An assignment is RELEVANT if its date is on or after the cutoff, or if it\n   spans a period that includes the cutoff.\n\n## Plan Presentation (MANDATORY)\n\nBefore starting any grading work, present a plan to the user. The plan MUST\ninclude:\n\n1. **Mode**: Single-repo or Bulk mode.\n2. **Date filter**: If applicable, show the cutoff date; otherwise \"All commits\".\n3. **Assignments discovered**: List all assignments found (date, topic,\n   source location). This requires running the full `grading-shared` Assignment\n   Discovery Protocol first.\n4. **Repositories to grade**:\n   - Single-repo: show the path and basename (or resolved symlink name if available).\n   - Bulk: list all discovered student repositories (resolved student name\n     from symlink where available, otherwise basename), with count.\n5. **Zielordner im `-T`-Repo**: the resolved `-T` root, the run folder\n   `\u003Ckohorte>\u002F\u003CYYYY-MM-DD>_\u003Cslug>\u002F` and whether it already exists (Probelauf,\n   read-only — see Zielordner section).\n6. **Anrede**: the word read from `\u003Ckohorte>\u002Fanrede.txt` (`Du`\u002F`Sie`); missing\n   file stops the run.\n7. **Output files** that will be generated (inside the run folder):\n   - Single-repo: `\u003Cbasename>_grading.md`, `\u003Cbasename>_email.json`,\n     `\u003Cbasename>_points.json`.\n   - Bulk: per-repo files + `GRADINGS.md` + shared `EMAIL.json` + `noten.tsv`.\n   - Date-filtered bulk also: `CLASS.md`.\n\nDisplay this plan and proceed immediately without waiting for confirmation.\n\n## Modes\n\n### 1. Single-repo mode\n\nUse this mode when a repository path is provided (with or without a date).\n\nProtocol:\n\n1. Treat the repository path as provided verbatim.\n2. Navigate to the student repository.\n3. Follow the `grading-shared` Pre-Grading Verification.\n4. Derive the output stem from `basename` of the repository path.\n5. Discover assignments using the `grading-shared` Assignment Discovery\n   Protocol and build a unified assignment list. If no assignment is found, stop\n   immediately. (Assignment files are NEVER inside the student repository.)\n6. If a date filter is active, filter commits to only those at or after the\n   cutoff date.\n7. Follow the `grading-shared` Repository Analysis Protocol to inspect the\n   repository history and actual commit content, not just commit messages.\n8. Evaluate work against the assignment periods and produce an updated grading\n   result in German.\n9. Do not write `INDIVIDUAL.md`.\n10. Do not write `CLASS.md`.\n11. Do not modify shared `EMAIL.json`.\n12. Generate `\u003Cbasename>_grading.md` as the repository grading report in German\n    (inside the `-T` run folder).\n13. Generate `\u003Cbasename>_email.json` as a JSON array with exactly one object,\n    following `grading-shared` Email JSON Structure and Email Body Format, using German body text.\n14. Generate `\u003Cbasename>_points.json` as the points sidecar (see\n    `grading-shared` Noten-TSV) — one object with `name`, `kind: \"homework\"`,\n    `klasse` and `assignments[{from, to, label, max, points}]`.\n\n### 2. Bulk mode\n\nUse this mode when no repository path is provided (with or without a date).\n\nProtocol:\n\n1. Discover student repositories following `grading-shared` Repository Structure\n   Discovery, Student Name Resolution via Symlinks, and Bulk Grading Protocol\n   directory exclusion rules. Each student repo's git working directory may be\n   one level deeper than the student directory. Broken name-symlinks are NOT\n   an error and NOT skipped: they mark students without a submitted\n   repository URL and are graded as no-repository cases (see No-Repository\n   Students below).\n2. Follow the `grading-shared` Bulk Grading Protocol for concurrency (default\n   max 5, ~3 second delay between runs).\n3. Each subagent writes only `\u003Cbasename>_grading.md`,\n     `\u003Cbasename>_email.json` and `\u003Cbasename>_points.json` in German, following\n     `grading-shared` Email JSON Structure, JSON Escaping Rules, and Email Body\n     Format, and the points-sidecar schema of the Noten-TSV section.\n     Subagents MUST use the exact `*_grading.md` section headings and order\n     defined in [REPORT-FORMAT.md](.\u002FREPORT-FORMAT.md). They MUST NOT produce\n     free-form reports with different lengths or different structures per\n     student.\n4. Subagents must never write shared `EMAIL.json` and never write `noten.tsv`.\n5. Continue until all repositories are processed.\n6. After all subagents finish:\n   - Generate `GRADINGS.md` in German with class-wide overview table.\n   - If a date filter is active, also generate `CLASS.md` in German.\n   - Aggregate per-repo `*_email.json` files into shared `EMAIL.json`\n     following `grading-shared` rules, including JSON Escaping Rules.\n   - Build `noten.tsv` (see below).\n7. Commit and push the run folder in the `-T` repo (see Commit-Protokoll).\n\n### 2b. Noten-TSV und Commit (nach der Aggregation)\n\n1. Roster beschaffen:\n   `wu lesson \u003CKLASSE\u002FFACH> roster > \u002Ftmp\u002Fopencode\u002Froster.tsv` (Fach aus der\n   `_class`-Adresse, z. B. `_class -> GRG-WMC\u002F3aaif` → `wu lesson 3aaif\u002Fwmc roster`).\n   Schlägt `wu` fehl: STOPP mit deutscher Meldung.\n2. **Probelauf (read-only, Pflicht):**\n\n   ```bash\n   ~\u002F.opencode\u002Fskills\u002Fgrading-shared\u002Femit-grade-tsv.py --roster \u002Ftmp\u002Fopencode\u002Froster.tsv\n   ```\n\n   Die Tabelle dem User zeigen.\n3. Erst danach schreiben:\n   `… emit-grade-tsv.py --roster \u002Ftmp\u002Fopencode\u002Froster.tsv --write` (ergibt\n   `noten.tsv` im Lauf-Ordner).\n4. `roster.tsv` ist nur ein Zwischenprodukt und wird nicht committet.\n5. **Commit-Protokoll:** im `-T`-Repo alle Ausgaben des Lauf-Ordners committen\n   und pushen — deutsche Commit-Message nach der Repo-Konvention mit\n   Issue-Nummer, z. B. `Abgaben 3AAIF 2026-11-01: Bewertungen, E-Mails und\n   Noten-TSV (#12)`. Ist keine Issue-Nummer bekannt, beim User nachfragen statt\n   raten. Niemals im öffentlichen Teaching-Repo committen.\n\n### 3. No-Repository Students (Broken Name-Symlinks)\n\nA broken name-symlink in the CWD marks a student who has not yet submitted\ntheir repository URL. Per `grading-shared` Broken Name-Symlinks (Missing\nRepository):\n\n1. Treat the student as a normal grading case (never stop, never skip).\n2. Grade without evidence: ALL Abgaben 0%, `Endbewertung: 0\u002F100`.\n3. Generate `\u003Cname>_grading.md` (mandatory structure, every section\n   explicitly stating \"kein Repository — keine Evidence\"), a\n   `\u003Cname>_email.json` whose body follows the Missing Repository Emphasis\n   variant (the URL submission is REQUIRED for a positive assessment), and a\n   `\u003Cname>_points.json` with 0 points for every Abgabe.\n4. Include the student in `GRADINGS.md` (0\u002F100) and in the shared\n   `EMAIL.json`.\n5. Skip all git commands and the Pre-Grading Verification for these students.\n\n## Assignment Matching\n\nAfter repository analysis, map the detected work onto the unified assignment list.\n\n### Step-by-Step Matching Process\n\n1. **Parse ALL assignment entries** from the unified list.\n\n2. **Match commits to assignments**:\n   - For each commit, determine which assignment it relates to.\n   - Use commit date + content to identify the relevant assignment period.\n   - A commit dated `2026-02-20` likely belongs to an assignment dated `2026-02-18`.\n\n3. **Build completion status for ALL assignments**:\n   - List all assignments in the unified list.\n   - Mark each as completed or missing.\n\n### Matching with Date Filter\n\nWhen a cutoff date is active:\n\n| Cutoff Date | Assignment Date | Match? | Reason |\n|-------------|-----------------|--------|--------|\n| 2026-02-10 | 2026-02-18 | YES | Assignment given after cutoff |\n| 2026-02-10 | 2026-02-05 | NO | Assignment before cutoff period |\n| 2026-02-10 | 2026-02-10 | YES | Exact match |\n| 2026-02-10 | 2026-03-01 | YES | Assignment within grading period |\n\n### Important Considerations\n\n- **Parse ALL entries before matching** — never stop at the first entry.\n- **Convert all dates to ISO format** — use the same format for comparison.\n- **Include assignments from the cutoff date onwards** — not just commits.\n- Clearly indicate in the report whether grading covers all commits or\n  from a specific date onwards.\n- Base judgments on actual code and text changes, not only on commit messages.\n\n## Bewertung pro Abgabe (CRITICAL)\n\nJede Abgabe zählt 100 Basispunkte. Bei N Abgaben sind maximal\nN × 100 Prozentpunkte erreichbar. Die Endbewertung in \u002F100 ergibt sich\naus `erreichte_Punkte \u002F max_Punkte × 100`.\n\n### Zwei Werte pro Abgabe\n\nFür jede Abgabe werden zwei Werte ermittelt:\n\n1. **Quality** (0–100%): Inhaltliche Bewertung — Korrektheit, Struktur,\n   Vollständigkeit, technisches Verständnis. 0% wenn keine Abgabe erkennbar.\n2. **Factor** (Pünktlichkeit): 1.0 (pünktlich) oder 0.75 (verspätet), gemäß\n   `grading-shared` Deadline Calculation.\n\n```\neffective_score = Quality × Factor\n```\n\n### Scoring Table (MANDATORY in every report and every email)\n\nJeder `*_grading.md`-Report und jede `*_email.json` MUSS exakt diese\nScoring-Tabelle enthalten.\n\n**Format in `*_grading.md` (Markdown-Tabelle):**\n\n```markdown\n| Abgabe | Thema | Quality | Factor | Effective |\n|--------|-------|---------|--------|-----------|\n| 1      | [Thema] | 80% | 1.0 | 80% |\n| 2       | [Thema] | 70% | 0.75 | 52.5% |\n| 3       | [Thema] | —  | —  | 0% |\n```\n\n**Format in `*_email.json` body (ASCII):**\n\n```\nAbgabe 1 [Thema]: 80% (pünktlich) -> 80 Punkte\nAbgabe 2 [Thema]: 70% (verspätet, daher 25% Abzug) -> 52.5 Punkte\nAbgabe 3 [Thema]: nicht abgegeben -> 0 Punkte\n```\n\n### Gesamtbewertung\n\n```\nerreichte_Punkte = sum(effective_score_i)\nmax_Punkte = Anzahl_Abgaben × 100\nEndbewertung = round(erreichte_Punkte \u002F max_Punkte × 100)\n```\n\nBeispiel: Fünf Abgaben, max. 500 Punkte:\n\n| Abgabe | Thema | Quality | Factor | Effective |\n|--------|-------|---------|--------|-----------|\n| 1      | Hono REST-API | 80% | 1.0 | 80% |\n| 2       | Fetch Response | 70% | 0.75 | 52.5% |\n| 3       | Promises | 90% | 1.0 | 90% |\n| 4       | Transpile | —  | —  | 0% |\n| 5       | KI-Provider | 60% | 1.0 | 60% |\n\nErreichte Punkte: 80 + 52.5 + 90 + 0 + 60 = 282.5 \u002F 500\nEndbewertung: 57\u002F100 (57%)\n\n### Abdeckungsquote (informativ)\n\n```\nAbdeckungsquote = (Anzahl Abgaben mit Quality > 0%) \u002F Anzahl_Abgaben × 100\n```\n\nNicht abgegeben = 0%, abgegeben (auch verspätet) zählt für die Quote.\nDie Abdeckungsquote ist rein informativ; sie geht NICHT zusätzlich in\ndie Endbewertung ein (fehlende Abgaben sind bereits mit 0% eingerechnet).\n\n### Edge Cases\n\n- **No assignments in period**: Report clearly, grade based on available work only.\n- **Empty repository**: Alle Abgaben 0% → Endbewertung 0\u002F100.\n- **Broken name-symlink (kein Repository)**: alle Abgaben 0% → Endbewertung\n  0\u002F100; E-Mail mit Missing Repository Emphasis (Pflicht) — siehe\n  `grading-shared` Broken Name-Symlinks.\n- **Late submissions**: Automatic 0.75 factor applied REGARDLESS of how late\n  the submission is (no graduated penalty); noted explicitly in every\n  relevant row of the scoring table.\n- **Deadline**: gemäß `grading-shared` Deadline Calculation — nächste UE nach\n  dem Aufgabendatum (via wu) bzw. eine explizite Deadline im Aufgabetext.\n\n## Outputs\n\nAll outputs are written into the `-T` run folder\n`\u003CT-Wurzel>\u002F\u003Ckohorte>\u002F\u003CYYYY-MM-DD>_\u003Cslug>\u002F` (see Zielordner section).\n\n### Single-repo mode\n\n- `\u003Cbasename>_grading.md` in German.\n- `\u003Cbasename>_email.json` as a one-entry JSON array following `grading-shared`\n  rules and Email Body Format, with German body text.\n- `\u003Cbasename>_points.json` as the points sidecar.\n\n### Bulk mode (all commits)\n\n- Per-repository `\u003Cbasename>_grading.md` files in German.\n- Per-repository `\u003Cbasename>_email.json` files following `grading-shared`\n  rules and Email Body Format, with German body text.\n- Per-repository `\u003Cbasename>_points.json` points sidecars.\n- `GRADINGS.md` with class-wide overview table in German.\n- `noten.tsv` as the Google-Doc import table (probelauf first, then written).\n- Shared `EMAIL.json`, created only after all per-repo outputs are finished.\n\n### Bulk mode (date-filtered)\n\n- Per-repository `\u003Cbasename>_grading.md` files in German.\n- Per-repository `\u003Cbasename>_email.json` files following `grading-shared`\n  rules and Email Body Format, with German body text.\n- Per-repository `\u003Cbasename>_points.json` points sidecars.\n- `GRADINGS.md` with class-wide overview table in German (includes cutoff date in header).\n- `CLASS.md` with anonymized class-wide patterns and teacher recommendations in German.\n- `noten.tsv` as the Google-Doc import table.\n- Shared `EMAIL.json`, created only after all per-repo outputs are finished.\n\n## GRADINGS.md Generation (Bulk Mode Only)\n\nAfter all per-repository grading is complete in bulk mode, generate `GRADINGS.md`\nas a class-wide overview table.\n\n### Content Requirements\n\n`GRADINGS.md` MUST include:\n\n1. A table with columns for student identifier (repository basename or name) and\n   final score (`Endbewertung`).\n2. Ordered alphabetically by student name, NOT by grade.\n3. Written in German.\n4. If date-filtered, include the cutoff date in the header.\n\n### Example Structure\n\n```markdown\n# Bewertungen\n\n| Name | Endbewertung |\n|------|-------------|\n| Huber Maria | 85\u002F100 |\n| Maier Thomas | 72\u002F100 |\n| Schmidt Anna | 91\u002F100 |\n```\n\n## CLASS.md Generation (Date-Filtered Bulk Mode Only)\n\nWhen a date filter is active in bulk mode, also generate `CLASS.md` as an\nanonymized class summary for the teacher.\n\n### Content Requirements\n\n`CLASS.md` MUST include:\n\n1. **Overview**: Summary of the grading period (cutoff date, number of\n   repositories graded).\n2. **Common Patterns**: Frequently observed strengths across submissions.\n3. **Common Weaknesses**: Recurring issues or mistakes.\n4. **Assignment Completion Statistics**: Aggregate completion ratios.\n5. **Teacher Recommendations**: Actionable suggestions for addressing issues.\n\n### Anonymity Rules\n\n- NEVER include student names or repository names that identify individuals.\n- Use generic terms in German: \"einige Schüler\", \"viele Abgaben\", \"vereinzelt\".\n- Focus on patterns, not individuals.\n- This file may be committed to a public repository.\n\n## Reporting Expectations\n\nThe mandatory `*_grading.md` structure, its section-content requirements, and\nthe subagent standardization rules are in [REPORT-FORMAT.md](.\u002FREPORT-FORMAT.md).\n\n## Email Body\n\nEvery `\u003Cbasename>_email.json` body MUST follow the `grading-shared` Email Body\nFormat section exactly: plain ASCII text with code blocks as the only allowed\nMarkdown, structured per the assignment grading email template, with subtle\npraise per the Praise Guidelines. All text MUST be in German.\n\nAdditionally, every repograde email body MUST summarize the following in the\nsame fixed structure for every student:\n\n1. greeting,\n2. automatic assessment disclaimer paragraph,\n3. grading period opening,\n4. commit activity summary,\n5. Abgaben-Übersicht (`Abgabe 1: …`, `Abgabe 2: …`),\n6. Bewertungs-Absätze pro Abgabe — each ending with `Bewertung: XX%`\n   and, if late, `(verspätet, daher 25% Abzug auf den erreichten Wert)`,\n7. scoring table (ASCII format per Bewertung pro Abgabe),\n8. Erreichte Punkte and Endbewertung summary,\n9. closing.\n\nWithin that fixed order, ensure that the combined Abgaben-Bewertung and\nscoring paragraphs clearly communicate code quality, missing work, lateness,\nand the final result. The Quality%, Factor, and Effective score of every Abgabe\nMUST all be visible per the Scoring Table format.\n\nDo not vary this structure between students. For students WITHOUT a\nrepository (broken name-symlink), the Missing Repository Emphasis variant\nreplaces paragraph groups 3–6 (see `grading-shared` Email Body Format).\n\n## Constraints\n\n- The grading work directory (typically `~\u002Fgits\u002F\u003Ckohorte>-\u003Cfach>\u002F`) must NOT\n  itself be inside a Git repository. All outputs go to the `-T` repo instead.\n- This skill must NOT clone student repositories; use `git pull` to update.\n- If uncommitted changes exist in any student repository, STOP IMMEDIATELY.\n- If a date is provided and invalid, STOP IMMEDIATELY.\n- Never commit student repositories or modify their history. The `-T` repo IS\n  committed (see Commit-Protokoll) — that is the only commit this skill makes.\n- All grading content follows `grading-shared` rules (German, second-person,\n  UTF-8 umlauts, email structure, email body format, missing email handling).\n- In single-repo mode, stop if no assignment source is found.\n- In single-repo mode, a provided repository path that is a broken symlink is\n  graded as a no-repository case (see No-Repository Students), not an error.\n- In single-repo mode, never write `INDIVIDUAL.md`, `CLASS.md`, or shared\n  `EMAIL.json`.\n- In bulk mode, generate `GRADINGS.md` after all per-repo grading is complete.\n- In date-filtered bulk mode, also generate `CLASS.md`.\n- In bulk mode, generate shared `EMAIL.json` only after all per-repo outputs\n  are complete.\n- Run `emit-grade-tsv.py` in dry-run mode first and show the table; write\n  `noten.tsv` only with `--write`.\n- Stop immediately when `\u003Ckohorte>\u002Fanrede.txt` is missing or invalid\n  (`grading-shared` Anrede-Gate).\n- Use proper quoting for paths with spaces.\n- Present the plan to the user BEFORE starting any grading work.\n- Use pure AI evaluation for all grading; never write grading scripts. The\n  sub-agent fan-out in bulk mode handles parallelism — do not write batch\n  processing scripts or evaluation programs.\n\n## Done when\n\n- [ ] Plan presented before any grading work: mode, date filter, assignments,\n  repositories, `-T` run folder (read-only Probelauf) and the Anrede source.\n- [ ] `anrede.txt` read via `read-anrede.sh`; a missing or invalid file stopped\n  the run before the first write.\n- [ ] Scoring table with Quality, Factor and Effective per Abgabe present in\n  every `*_grading.md` and every email body.\n- [ ] Single-repo mode: `\u003Cbasename>_grading.md`, `\u003Cbasename>_email.json` and\n  `\u003Cbasename>_points.json` written in the `-T` run folder.\n- [ ] Bulk mode: per-repo files plus `GRADINGS.md`, shared `EMAIL.json` and\n  `noten.tsv` (dry-run table shown first, `--write` only after) generated once\n  the last subagent finished.\n- [ ] Date-filtered bulk mode additionally produced `CLASS.md` without student\n  names.\n- [ ] No-repository students (broken name-symlinks) graded 0\u002F100 with the\n  Missing Repository Emphasis email, not skipped.\n- [ ] Student repositories read-only: no commit, no history change, no clone;\n  only the run folder committed and pushed in the `-T` repo.\n","# Repograde Skill\n\n## Purpose\n\nThis skill is the canonical workflow for grading student Git repositories.\nIt handles both full-history grading and date-filtered grading (commits\nfrom a specified cutoff date onwards) in a single unified workflow.\n\n## Output Language: MANDATORY GERMAN\n\nFollow the `grading-shared` **Output Language** rule: natural German with proper\nUTF-8 umlauts (ä, ö, ü, ß), never English.\n\n## Dependencies\n\nThis skill relies on `grading-shared` for: Anrede-Gate (`anrede.txt`), email\nformulas, second-person address rules, database lookup, email JSON structure,\nname parsing from repository basename (CRITICAL: last word = first name,\neverything before it = last name), repository analysis protocol, assignment\ndiscovery protocol (Aufgaben-Discovery), bulk grading concurrency, German\u002FUTF-8\nconstraints, JSON escaping rules, email body format, praise guidelines,\nNoten-TSV and reporting protocol.\n\nDerive output filenames from the repository basename, while using the provided\nrepository path verbatim to locate the repository.\n\n## Consistency Goal (CRITICAL)\n\nThe grading output of this skill MUST be highly standardized across repositories\nand across subagents. Do NOT improvise the structure, heading names, section\norder, or overall depth.\n\nEvery `*_grading.md` file generated by this skill MUST:\n\n1. use the exact section order defined in [REPORT-FORMAT.md](.\u002FREPORT-FORMAT.md),\n2. include all mandatory numeric facts when evidence exists,\n3. explicitly say when evidence is missing or unclear instead of silently\n   omitting a section,\n4. stay within the requested level of detail rather than expanding into a\n   free-form essay.\n\nEvery `*_email.json` body generated by this skill MUST:\n\n1. follow the exact paragraph order defined by `grading-shared` for assignment\n   grading emails,\n2. summarize the same core facts as the grading report,\n3. keep a consistent scope and length across students.\n\n## Execution Context\n\nThis skill operates from a local folder (current working directory), NOT from\nwithin a Git repository. Calling this skill from inside a Git repository is\nan error.\n\nThe CWD contains student Git repositories as subdirectories. These may be\nstructured as `STUDENT_DIR\u002FINNER_PROJECT\u002F.git` (two levels deep). The CWD may\nalso contain name-based symlinks (e.g., `Lastname Firstname -> STUDENT_ID`)\nthat provide the student's real name. A BROKEN name-symlink (target does not\nexist) means the student has not yet submitted their repository URL — see\n`grading-shared` Broken Name-Symlinks (Missing Repository).\n\nFollow `grading-shared` Repository Structure Discovery (Inner Git Repository\nDiscovery) before running any git commands. Use `grading-shared` Student Name\nResolution via Symlinks to determine the student's name.\n\nThe CWD may also contain a `_class` symlink pointing to the corresponding class\nfolder in the teaching repository (e.g., `_class -> \u002Fhome\u002Fgeorg\u002Frepos\u002FGRG-SWP\u002F2ahwii\u002F`).\nThis symlink provides access to assignments and lesson materials.\n\n## Zielordner im `-T`-Repo (CRITICAL)\n\nAlle Ausgaben dieses Skills werden im **privaten `-T`-Repo** abgelegt, niemals\nim Arbeitsverzeichnis mit den Schüler-Repos und niemals im öffentlichen\nTeaching-Repo.\n\nDer normale Arbeitsplatz ist `~\u002Fgits\u002F\u003Ckohorte>-\u003Cfach>\u002F` (z. B.\n`~\u002Fgits\u002F3aaif-wmc\u002F`): **kein** Git-Repo, darin die Namens-Symlinks auf die\nSchüler-Repos und der `_class`-Symlink ins öffentliche Klassen-Repo:\n\n```\n~\u002Fgits\u002F3aaif-wmc\u002F_class -> \u002Fhome\u002Fgeorg\u002Fr\u002FGRG-WMC\u002F3aaif\n~\u002Fgits\u002F3aaif-wmc\u002FAbazi Hamza -> Hamza473A\n```\n\nAuflösung (in dieser Reihenfolge):\n\n1. **CWD liegt bereits in einem `-T`-Repo:** `git rev-parse --show-toplevel`\n   liefert einen Pfad, dessen Basename auf `-T` endet → das ist die Wurzel.\n2. **Sonst über `_class`:** `readlink -f` auf `_class` (immer auflösen — `~\u002Fr`\n   ist selbst ein Symlink auf `repos\u002Fgeorgernstgraf\u002F`); das Ziel hat die Form\n   `\u002F…\u002FGRG-\u003CFACH>\u002F\u003Ckohorte>` → `-T`-Wurzel ist das Schwesterverzeichnis\n   `\u002F…\u002FGRG-\u003CFACH>-T`, die Kohorte ist der Basename des Ziels.\n3. **Sonst:** STOPP und den User fragen (kein Raten).\n\nZielordner: `\u003CT-Wurzel>\u002F\u003Ckohorte>\u002F\u003CYYYY-MM-DD>_\u003Cslug>\u002F`\n(z. B. `~\u002Fr\u002FGRG-WMC-T\u002F3aaif\u002F2026-11-08_repokontrolle\u002F`)\n\n- `\u003CYYYY-MM-DD>` = heutiges Datum des Laufs.\n- `\u003Cslug>` = kurzer Lauf-Bezeichner (z. B. `repos`, `repokontrolle`); aus dem\n  User-Auftrag ableiten, sonst `repograde`.\n- Ordner **bei Bedarf anlegen** (`mkdir -p`) — ein neuer Semester-\u002FLauf-Ordner\n  ist der Normalfall, kein Fehler.\n\nVor dem ersten Schreibzugriff läuft ein **Probelauf (read-only)**: der\naufgelöste `-T`-Ordner, der Zielordner und die geplante Dateiliste werden\nangezeigt; es wird nichts angelegt und nichts geschrieben. Erst danach wird\ngearbeitet.\n\nDie Schüler-Repos bleiben im CWD und werden nur gelesen. `roster.tsv` ist eine\nZwischendatei und landet unter `\u002Ftmp\u002Fopencode\u002F` (nicht im Lauf-Ordner, nicht im\nCommit). Committet wird am Ende im `-T`-Repo (siehe Commit-Protokoll).\n\n## Input\n\nArguments are inferred from the user's request. Parse the user message to\ndetermine the mode:\n\n| User provides | Mode |\n|---------------|------|\n| Nothing (just \"grade\" or similar) | Bulk mode, all commits |\n| Repository path only | Single-repo, all commits |\n| Date only (ISO format YYYY-MM-DD) | Bulk mode, filtered commits |\n| Date + repository path | Single-repo, filtered commits |\n\n### Date Validation\n\nIf a date argument is detected, it MUST strictly follow ISO 8601:\n\n```\nYYYY-MM-DD\n```\n\nValid: `2025-03-15`, `2024-12-01`\nInvalid: `2025-3-15`, `15-03-2025`, `2025\u002F03\u002F15`, `2025-03`\n\nIf the date is invalid, STOP IMMEDIATELY with error:\n\"Invalid date format: '[input]'. Expected ISO date format: YYYY-MM-DD (e.g., 2025-03-15)\"\n\n### Date Filtering Logic\n\nWhen a date is provided:\n1. Parse the cutoff date as `YYYY-MM-DDT00:00:00` (midnight at start of day).\n2. Only inspect commits where `commit_date >= cutoff_date`.\n3. Use `git log --after=\"YYYY-MM-DD\"` to filter commits.\n4. An assignment is RELEVANT if its date is on or after the cutoff, or if it\n   spans a period that includes the cutoff.\n\n## Plan Presentation (MANDATORY)\n\nBefore starting any grading work, present a plan to the user. The plan MUST\ninclude:\n\n1. **Mode**: Single-repo or Bulk mode.\n2. **Date filter**: If applicable, show the cutoff date; otherwise \"All commits\".\n3. **Assignments discovered**: List all assignments found (date, topic,\n   source location). This requires running the full `grading-shared` Assignment\n   Discovery Protocol first.\n4. **Repositories to grade**:\n   - Single-repo: show the path and basename (or resolved symlink name if available).\n   - Bulk: list all discovered student repositories (resolved student name\n     from symlink where available, otherwise basename), with count.\n5. **Zielordner im `-T`-Repo**: the resolved `-T` root, the run folder\n   `\u003Ckohorte>\u002F\u003CYYYY-MM-DD>_\u003Cslug>\u002F` and whether it already exists (Probelauf,\n   read-only — see Zielordner section).\n6. **Anrede**: the word read from `\u003Ckohorte>\u002Fanrede.txt` (`Du`\u002F`Sie`); missing\n   file stops the run.\n7. **Output files** that will be generated (inside the run folder):\n   - Single-repo: `\u003Cbasename>_grading.md`, `\u003Cbasename>_email.json`,\n     `\u003Cbasename>_points.json`.\n   - Bulk: per-repo files + `GRADINGS.md` + shared `EMAIL.json` + `noten.tsv`.\n   - Date-filtered bulk also: `CLASS.md`.\n\nDisplay this plan and proceed immediately without waiting for confirmation.\n\n## Modes\n\n### 1. Single-repo mode\n\nUse this mode when a repository path is provided (with or without a date).\n\nProtocol:\n\n1. Treat the repository path as provided verbatim.\n2. Navigate to the student repository.\n3. Follow the `grading-shared` Pre-Grading Verification.\n4. Derive the output stem from `basename` of the repository path.\n5. Discover assignments using the `grading-shared` Assignment Discovery\n   Protocol and build a unified assignment list. If no assignment is found, stop\n   immediately. (Assignment files are NEVER inside the student repository.)\n6. If a date filter is active, filter commits to only those at or after the\n   cutoff date.\n7. Follow the `grading-shared` Repository Analysis Protocol to inspect the\n   repository history and actual commit content, not just commit messages.\n8. Evaluate work against the assignment periods and produce an updated grading\n   result in German.\n9. Do not write `INDIVIDUAL.md`.\n10. Do not write `CLASS.md`.\n11. Do not modify shared `EMAIL.json`.\n12. Generate `\u003Cbasename>_grading.md` as the repository grading report in German\n    (inside the `-T` run folder).\n13. Generate `\u003Cbasename>_email.json` as a JSON array with exactly one object,\n    following `grading-shared` Email JSON Structure and Email Body Format, using German body text.\n14. Generate `\u003Cbasename>_points.json` as the points sidecar (see\n    `grading-shared` Noten-TSV) — one object with `name`, `kind: \"homework\"`,\n    `klasse` and `assignments[{from, to, label, max, points}]`.\n\n### 2. Bulk mode\n\nUse this mode when no repository path is provided (with or without a date).\n\nProtocol:\n\n1. Discover student repositories following `grading-shared` Repository Structure\n   Discovery, Student Name Resolution via Symlinks, and Bulk Grading Protocol\n   directory exclusion rules. Each student repo's git working directory may be\n   one level deeper than the student directory. Broken name-symlinks are NOT\n   an error and NOT skipped: they mark students without a submitted\n   repository URL and are graded as no-repository cases (see No-Repository\n   Students below).\n2. Follow the `grading-shared` Bulk Grading Protocol for concurrency (default\n   max 5, ~3 second delay between runs).\n3. Each subagent writes only `\u003Cbasename>_grading.md`,\n     `\u003Cbasename>_email.json` and `\u003Cbasename>_points.json` in German, following\n     `grading-shared` Email JSON Structure, JSON Escaping Rules, and Email Body\n     Format, and the points-sidecar schema of the Noten-TSV section.\n     Subagents MUST use the exact `*_grading.md` section headings and order\n     defined in [REPORT-FORMAT.md](.\u002FREPORT-FORMAT.md). They MUST NOT produce\n     free-form reports with different lengths or different structures per\n     student.\n4. Subagents must never write shared `EMAIL.json` and never write `noten.tsv`.\n5. Continue until all repositories are processed.\n6. After all subagents finish:\n   - Generate `GRADINGS.md` in German with class-wide overview table.\n   - If a date filter is active, also generate `CLASS.md` in German.\n   - Aggregate per-repo `*_email.json` files into shared `EMAIL.json`\n     following `grading-shared` rules, including JSON Escaping Rules.\n   - Build `noten.tsv` (see below).\n7. Commit and push the run folder in the `-T` repo (see Commit-Protokoll).\n\n### 2b. Noten-TSV und Commit (nach der Aggregation)\n\n1. Roster beschaffen:\n   `wu lesson \u003CKLASSE\u002FFACH> roster > \u002Ftmp\u002Fopencode\u002Froster.tsv` (Fach aus der\n   `_class`-Adresse, z. B. `_class -> GRG-WMC\u002F3aaif` → `wu lesson 3aaif\u002Fwmc roster`).\n   Schlägt `wu` fehl: STOPP mit deutscher Meldung.\n2. **Probelauf (read-only, Pflicht):**\n\n   ```bash\n   ~\u002F.opencode\u002Fskills\u002Fgrading-shared\u002Femit-grade-tsv.py --roster \u002Ftmp\u002Fopencode\u002Froster.tsv\n   ```\n\n   Die Tabelle dem User zeigen.\n3. Erst danach schreiben:\n   `… emit-grade-tsv.py --roster \u002Ftmp\u002Fopencode\u002Froster.tsv --write` (ergibt\n   `noten.tsv` im Lauf-Ordner).\n4. `roster.tsv` ist nur ein Zwischenprodukt und wird nicht committet.\n5. **Commit-Protokoll:** im `-T`-Repo alle Ausgaben des Lauf-Ordners committen\n   und pushen — deutsche Commit-Message nach der Repo-Konvention mit\n   Issue-Nummer, z. B. `Abgaben 3AAIF 2026-11-01: Bewertungen, E-Mails und\n   Noten-TSV (#12)`. Ist keine Issue-Nummer bekannt, beim User nachfragen statt\n   raten. Niemals im öffentlichen Teaching-Repo committen.\n\n### 3. No-Repository Students (Broken Name-Symlinks)\n\nA broken name-symlink in the CWD marks a student who has not yet submitted\ntheir repository URL. Per `grading-shared` Broken Name-Symlinks (Missing\nRepository):\n\n1. Treat the student as a normal grading case (never stop, never skip).\n2. Grade without evidence: ALL Abgaben 0%, `Endbewertung: 0\u002F100`.\n3. Generate `\u003Cname>_grading.md` (mandatory structure, every section\n   explicitly stating \"kein Repository — keine Evidence\"), a\n   `\u003Cname>_email.json` whose body follows the Missing Repository Emphasis\n   variant (the URL submission is REQUIRED for a positive assessment), and a\n   `\u003Cname>_points.json` with 0 points for every Abgabe.\n4. Include the student in `GRADINGS.md` (0\u002F100) and in the shared\n   `EMAIL.json`.\n5. Skip all git commands and the Pre-Grading Verification for these students.\n\n## Assignment Matching\n\nAfter repository analysis, map the detected work onto the unified assignment list.\n\n### Step-by-Step Matching Process\n\n1. **Parse ALL assignment entries** from the unified list.\n\n2. **Match commits to assignments**:\n   - For each commit, determine which assignment it relates to.\n   - Use commit date + content to identify the relevant assignment period.\n   - A commit dated `2026-02-20` likely belongs to an assignment dated `2026-02-18`.\n\n3. **Build completion status for ALL assignments**:\n   - List all assignments in the unified list.\n   - Mark each as completed or missing.\n\n### Matching with Date Filter\n\nWhen a cutoff date is active:\n\n| Cutoff Date | Assignment Date | Match? | Reason |\n|-------------|-----------------|--------|--------|\n| 2026-02-10 | 2026-02-18 | YES | Assignment given after cutoff |\n| 2026-02-10 | 2026-02-05 | NO | Assignment before cutoff period |\n| 2026-02-10 | 2026-02-10 | YES | Exact match |\n| 2026-02-10 | 2026-03-01 | YES | Assignment within grading period |\n\n### Important Considerations\n\n- **Parse ALL entries before matching** — never stop at the first entry.\n- **Convert all dates to ISO format** — use the same format for comparison.\n- **Include assignments from the cutoff date onwards** — not just commits.\n- Clearly indicate in the report whether grading covers all commits or\n  from a specific date onwards.\n- Base judgments on actual code and text changes, not only on commit messages.\n\n## Bewertung pro Abgabe (CRITICAL)\n\nJede Abgabe zählt 100 Basispunkte. Bei N Abgaben sind maximal\nN × 100 Prozentpunkte erreichbar. Die Endbewertung in \u002F100 ergibt sich\naus `erreichte_Punkte \u002F max_Punkte × 100`.\n\n### Zwei Werte pro Abgabe\n\nFür jede Abgabe werden zwei Werte ermittelt:\n\n1. **Quality** (0–100%): Inhaltliche Bewertung — Korrektheit, Struktur,\n   Vollständigkeit, technisches Verständnis. 0% wenn keine Abgabe erkennbar.\n2. **Factor** (Pünktlichkeit): 1.0 (pünktlich) oder 0.75 (verspätet), gemäß\n   `grading-shared` Deadline Calculation.\n\n```\neffective_score = Quality × Factor\n```\n\n### Scoring Table (MANDATORY in every report and every email)\n\nJeder `*_grading.md`-Report und jede `*_email.json` MUSS exakt diese\nScoring-Tabelle enthalten.\n\n**Format in `*_grading.md` (Markdown-Tabelle):**\n\n```markdown\n| Abgabe | Thema | Quality | Factor | Effective |\n|--------|-------|---------|--------|-----------|\n| 1      | [Thema] | 80% | 1.0 | 80% |\n| 2       | [Thema] | 70% | 0.75 | 52.5% |\n| 3       | [Thema] | —  | —  | 0% |\n```\n\n**Format in `*_email.json` body (ASCII):**\n\n```\nAbgabe 1 [Thema]: 80% (pünktlich) -> 80 Punkte\nAbgabe 2 [Thema]: 70% (verspätet, daher 25% Abzug) -> 52.5 Punkte\nAbgabe 3 [Thema]: nicht abgegeben -> 0 Punkte\n```\n\n### Gesamtbewertung\n\n```\nerreichte_Punkte = sum(effective_score_i)\nmax_Punkte = Anzahl_Abgaben × 100\nEndbewertung = round(erreichte_Punkte \u002F max_Punkte × 100)\n```\n\nBeispiel: Fünf Abgaben, max. 500 Punkte:\n\n| Abgabe | Thema | Quality | Factor | Effective |\n|--------|-------|---------|--------|-----------|\n| 1      | Hono REST-API | 80% | 1.0 | 80% |\n| 2       | Fetch Response | 70% | 0.75 | 52.5% |\n| 3       | Promises | 90% | 1.0 | 90% |\n| 4       | Transpile | —  | —  | 0% |\n| 5       | KI-Provider | 60% | 1.0 | 60% |\n\nErreichte Punkte: 80 + 52.5 + 90 + 0 + 60 = 282.5 \u002F 500\nEndbewertung: 57\u002F100 (57%)\n\n### Abdeckungsquote (informativ)\n\n```\nAbdeckungsquote = (Anzahl Abgaben mit Quality > 0%) \u002F Anzahl_Abgaben × 100\n```\n\nNicht abgegeben = 0%, abgegeben (auch verspätet) zählt für die Quote.\nDie Abdeckungsquote ist rein informativ; sie geht NICHT zusätzlich in\ndie Endbewertung ein (fehlende Abgaben sind bereits mit 0% eingerechnet).\n\n### Edge Cases\n\n- **No assignments in period**: Report clearly, grade based on available work only.\n- **Empty repository**: Alle Abgaben 0% → Endbewertung 0\u002F100.\n- **Broken name-symlink (kein Repository)**: alle Abgaben 0% → Endbewertung\n  0\u002F100; E-Mail mit Missing Repository Emphasis (Pflicht) — siehe\n  `grading-shared` Broken Name-Symlinks.\n- **Late submissions**: Automatic 0.75 factor applied REGARDLESS of how late\n  the submission is (no graduated penalty); noted explicitly in every\n  relevant row of the scoring table.\n- **Deadline**: gemäß `grading-shared` Deadline Calculation — nächste UE nach\n  dem Aufgabendatum (via wu) bzw. eine explizite Deadline im Aufgabetext.\n\n## Outputs\n\nAll outputs are written into the `-T` run folder\n`\u003CT-Wurzel>\u002F\u003Ckohorte>\u002F\u003CYYYY-MM-DD>_\u003Cslug>\u002F` (see Zielordner section).\n\n### Single-repo mode\n\n- `\u003Cbasename>_grading.md` in German.\n- `\u003Cbasename>_email.json` as a one-entry JSON array following `grading-shared`\n  rules and Email Body Format, with German body text.\n- `\u003Cbasename>_points.json` as the points sidecar.\n\n### Bulk mode (all commits)\n\n- Per-repository `\u003Cbasename>_grading.md` files in German.\n- Per-repository `\u003Cbasename>_email.json` files following `grading-shared`\n  rules and Email Body Format, with German body text.\n- Per-repository `\u003Cbasename>_points.json` points sidecars.\n- `GRADINGS.md` with class-wide overview table in German.\n- `noten.tsv` as the Google-Doc import table (probelauf first, then written).\n- Shared `EMAIL.json`, created only after all per-repo outputs are finished.\n\n### Bulk mode (date-filtered)\n\n- Per-repository `\u003Cbasename>_grading.md` files in German.\n- Per-repository `\u003Cbasename>_email.json` files following `grading-shared`\n  rules and Email Body Format, with German body text.\n- Per-repository `\u003Cbasename>_points.json` points sidecars.\n- `GRADINGS.md` with class-wide overview table in German (includes cutoff date in header).\n- `CLASS.md` with anonymized class-wide patterns and teacher recommendations in German.\n- `noten.tsv` as the Google-Doc import table.\n- Shared `EMAIL.json`, created only after all per-repo outputs are finished.\n\n## GRADINGS.md Generation (Bulk Mode Only)\n\nAfter all per-repository grading is complete in bulk mode, generate `GRADINGS.md`\nas a class-wide overview table.\n\n### Content Requirements\n\n`GRADINGS.md` MUST include:\n\n1. A table with columns for student identifier (repository basename or name) and\n   final score (`Endbewertung`).\n2. Ordered alphabetically by student name, NOT by grade.\n3. Written in German.\n4. If date-filtered, include the cutoff date in the header.\n\n### Example Structure\n\n```markdown\n# Bewertungen\n\n| Name | Endbewertung |\n|------|-------------|\n| Huber Maria | 85\u002F100 |\n| Maier Thomas | 72\u002F100 |\n| Schmidt Anna | 91\u002F100 |\n```\n\n## CLASS.md Generation (Date-Filtered Bulk Mode Only)\n\nWhen a date filter is active in bulk mode, also generate `CLASS.md` as an\nanonymized class summary for the teacher.\n\n### Content Requirements\n\n`CLASS.md` MUST include:\n\n1. **Overview**: Summary of the grading period (cutoff date, number of\n   repositories graded).\n2. **Common Patterns**: Frequently observed strengths across submissions.\n3. **Common Weaknesses**: Recurring issues or mistakes.\n4. **Assignment Completion Statistics**: Aggregate completion ratios.\n5. **Teacher Recommendations**: Actionable suggestions for addressing issues.\n\n### Anonymity Rules\n\n- NEVER include student names or repository names that identify individuals.\n- Use generic terms in German: \"einige Schüler\", \"viele Abgaben\", \"vereinzelt\".\n- Focus on patterns, not individuals.\n- This file may be committed to a public repository.\n\n## Reporting Expectations\n\nThe mandatory `*_grading.md` structure, its section-content requirements, and\nthe subagent standardization rules are in [REPORT-FORMAT.md](.\u002FREPORT-FORMAT.md).\n\n## Email Body\n\nEvery `\u003Cbasename>_email.json` body MUST follow the `grading-shared` Email Body\nFormat section exactly: plain ASCII text with code blocks as the only allowed\nMarkdown, structured per the assignment grading email template, with subtle\npraise per the Praise Guidelines. All text MUST be in German.\n\nAdditionally, every repograde email body MUST summarize the following in the\nsame fixed structure for every student:\n\n1. greeting,\n2. automatic assessment disclaimer paragraph,\n3. grading period opening,\n4. commit activity summary,\n5. Abgaben-Übersicht (`Abgabe 1: …`, `Abgabe 2: …`),\n6. Bewertungs-Absätze pro Abgabe — each ending with `Bewertung: XX%`\n   and, if late, `(verspätet, daher 25% Abzug auf den erreichten Wert)`,\n7. scoring table (ASCII format per Bewertung pro Abgabe),\n8. Erreichte Punkte and Endbewertung summary,\n9. closing.\n\nWithin that fixed order, ensure that the combined Abgaben-Bewertung and\nscoring paragraphs clearly communicate code quality, missing work, lateness,\nand the final result. The Quality%, Factor, and Effective score of every Abgabe\nMUST all be visible per the Scoring Table format.\n\nDo not vary this structure between students. For students WITHOUT a\nrepository (broken name-symlink), the Missing Repository Emphasis variant\nreplaces paragraph groups 3–6 (see `grading-shared` Email Body Format).\n\n## Constraints\n\n- The grading work directory (typically `~\u002Fgits\u002F\u003Ckohorte>-\u003Cfach>\u002F`) must NOT\n  itself be inside a Git repository. All outputs go to the `-T` repo instead.\n- This skill must NOT clone student repositories; use `git pull` to update.\n- If uncommitted changes exist in any student repository, STOP IMMEDIATELY.\n- If a date is provided and invalid, STOP IMMEDIATELY.\n- Never commit student repositories or modify their history. The `-T` repo IS\n  committed (see Commit-Protokoll) — that is the only commit this skill makes.\n- All grading content follows `grading-shared` rules (German, second-person,\n  UTF-8 umlauts, email structure, email body format, missing email handling).\n- In single-repo mode, stop if no assignment source is found.\n- In single-repo mode, a provided repository path that is a broken symlink is\n  graded as a no-repository case (see No-Repository Students), not an error.\n- In single-repo mode, never write `INDIVIDUAL.md`, `CLASS.md`, or shared\n  `EMAIL.json`.\n- In bulk mode, generate `GRADINGS.md` after all per-repo grading is complete.\n- In date-filtered bulk mode, also generate `CLASS.md`.\n- In bulk mode, generate shared `EMAIL.json` only after all per-repo outputs\n  are complete.\n- Run `emit-grade-tsv.py` in dry-run mode first and show the table; write\n  `noten.tsv` only with `--write`.\n- Stop immediately when `\u003Ckohorte>\u002Fanrede.txt` is missing or invalid\n  (`grading-shared` Anrede-Gate).\n- Use proper quoting for paths with spaces.\n- Present the plan to the user BEFORE starting any grading work.\n- Use pure AI evaluation for all grading; never write grading scripts. The\n  sub-agent fan-out in bulk mode handles parallelism — do not write batch\n  processing scripts or evaluation programs.\n\n## Done when\n\n- [ ] Plan presented before any grading work: mode, date filter, assignments,\n  repositories, `-T` run folder (read-only Probelauf) and the Anrede source.\n- [ ] `anrede.txt` read via `read-anrede.sh`; a missing or invalid file stopped\n  the run before the first write.\n- [ ] Scoring table with Quality, Factor and Effective per Abgabe present in\n  every `*_grading.md` and every email body.\n- [ ] Single-repo mode: `\u003Cbasename>_grading.md`, `\u003Cbasename>_email.json` and\n  `\u003Cbasename>_points.json` written in the `-T` run folder.\n- [ ] Bulk mode: per-repo files plus `GRADINGS.md`, shared `EMAIL.json` and\n  `noten.tsv` (dry-run table shown first, `--write` only after) generated once\n  the last subagent finished.\n- [ ] Date-filtered bulk mode additionally produced `CLASS.md` without student\n  names.\n- [ ] No-repository students (broken name-symlinks) graded 0\u002F100 with the\n  Missing Repository Emphasis email, not skipped.\n- [ ] Student repositories read-only: no commit, no history change, no clone;\n  only the run folder committed and pushed in the `-T` repo.\n",{"name":5,"license":15,"metadata":35,"description":7,"compatibility":22},{"scope":20,"category":23},"main","adef05bd2193559aced970b8591fc8182a916301","skills\u002Frepograde",0,"https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers","https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf","https:\u002F\u002Fwww.spengergasse.at\u002F","2026-11-11 16:51:38",{"source":8,"skillName":5,"commands":45,"prompt":55,"zipAvailable":56},[46,49,52],{"tool":47,"command":48},"npx","npx skills add georgernstgraf\u002Fopencode-helpers --skill repograde",{"tool":50,"command":51},"bunx","bunx skills add georgernstgraf\u002Fopencode-helpers --skill repograde",{"tool":53,"command":54},"pnpm","pnpm dlx skills add georgernstgraf\u002Fopencode-helpers --skill repograde","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Frepograde\u002FSKILL.md",true,[58],{"path":59,"resourceType":60,"resourceTypeDesc":61,"sizeBytes":62,"sourceHtmlUrl":63},"REPORT-FORMAT.md","REFERENCE","参考文档",5935,"https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Frepograde\u002FREPORT-FORMAT.md",[65,83,110,125,137,161],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":76,"publishedAt":30},"01M6CVKZ762FN4SW18V26P65TD","teach","Teach the user a new skill or concept, within this workspace.","https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Fteach\u002FSKILL.md",[71],{"categoryNo":72,"categoryName":73,"taxonomyType":74,"taxonomyTypeDesc":75},"01JBSEEDCAT000000000000039","教师与教育","PROFESSION","适用职业",[67,77,78,79,80,81,82],"false","new","concept","user","new skill","workspace",{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":89,"publishedAt":30},"01M6CVKVT6ZVYN2XPESS5EGDKE","sync-upstream-skills","Re-transplant owned skills from their mattpocock upstream after a git pull, applying upstream content changes while preserving opencode-native frontmatter. Also checks for duplicate skill names and dangling cross-skill references. Use when the user says \"sync skills\", \"refresh from upstream\", \"pull matt's skills\", \"sync upstream\", \"update the transplanted skills\", or wants to bring the owned transplanted skills up to date. Do not use to add or rename a transplanted skill — that stays manual.","https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Fsync-upstream-skills\u002FSKILL.md",[],[90,91,92,93,94,95,96,22,97,98,99,100,101,102,103,104,105,106,80,107,108,109],"sync","upstream","sync upstream","sync upstream skills","pull","references","refresh","duplicate skill","duplicate","frontmatter","native","changes","up","when","re","for","bring","content","use","git",{"skillNo":111,"name":112,"nameZh":6,"description":113,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":114,"categories":115,"keywords":116,"publishedAt":30},"01M6CVKF9MVFPHBH3W2D5ETEB6","projectgrade","Grade student project repositories based on Git commits, GitHub Issues, and Pull Requests. Use when the user says \"projectgrade\", \"grade the project\", \"bewerte das Projekt\", \"Projektarbeit benoten\", or asks for a holistic grading of a collaborative repository from inside it, based on commits, issues, reviews and PRs. Do not use for per-lesson assignments (use repograde) or for knowledge-check exams (use knowledge-assessment).","https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Fprojectgrade\u002FSKILL.md",[],[112,28,117,118,119,26,120,23,121,22,122,20,123,124,94,109],"requests","github issues","git commits","project","github","pull requests","issues","commits",{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":30},"01M6CVKA8J284DZTBE7QRN45SG","lehrplan","Richtet österreichische HTL-Unterrichts-Repositorien ein und pflegt sie — drei Kernaufgaben: das gesetzliche Lehrplan-Material eines Ausbildungszweigs (z. B. WII, WIT, KIF) aus dem RIS beschaffen inklusive jährlichem Novellen-Check, den Lehrplan eines konkreten Gegenstands aus dem Gesetz extrahieren (mit Erläuterung pro Lernziel: was der Inhalt tatsächlich IST, plus praktische Anwendungen), und Semesterpläne interaktiv entwerfen. Use when der Nutzer 'Lehrplan', 'Unterrichtsvorbereitung prüfen', 'Lehrplan auf Novellen prüfen', 'RIS sync', 'Gesetzesmaterial holen', 'Lehrplan extrahieren', 'Jahrespläne neu ziehen', 'Erläuterungen ergänzen', 'Semesterplan erstellen\u002Füberarbeiten' oder 'Einheiten erstellen' sagt, oder wenn in einem Repo gearbeitet wird, das der lehrplan\u002F-Konvention folgt. Do not use for Prepared Lessons (create-lesson), Aufgaben im Kohortenordner (homework) oder Wissensüberprüfungen (knowledge-exam).","https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Flehrplan\u002FSKILL.md",[],[127,132,133,134,135,90,136,23,19,22],"material","drei","pro","curriculum","check",{"skillNo":138,"name":139,"nameZh":6,"description":140,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":141,"categories":142,"keywords":148,"publishedAt":30},"01M6CVK6QMR16MSMS2MRG097GV","knowledge-persistence","Persist session context into the structured docs\u002Fai knowledge files (OKF bundle; committed and pushed at the end). Use when the user says \"remember\", \"merk dir das\", \"save context\", \"persist knowledge\" or \"update knowledge file\", at a session checkpoint, or when an observation in this session contradicts docs\u002Fai\u002F or AGENTS.md. Do not use for reading the knowledge files at session start — that is plain bootstrapping.","https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Fknowledge-persistence\u002FSKILL.md",[143],{"categoryNo":144,"categoryName":145,"taxonomyType":146,"taxonomyTypeDesc":147},"01JBSEEDCAT000000000000021","资料检索与研究","SCENARIO","使用场景",[149,150,151,152,153,22,154,155,156,157,158,159,160],"knowledge persistence","persistence","knowledge","context","docs","documentation","workflow","files","session context","session","persist","structured",{"skillNo":162,"name":163,"nameZh":6,"description":164,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":165,"categories":166,"keywords":168,"publishedAt":30},"01M6CVK3ED9F94R65AD5PG0RRH","knowledge-exam","Generate German knowledge-check exams and solution files from the taught material (class Git history + WebUntis Lehrstoff). Use when the user says \"Wissensüberprüfung erstellen\", \"Knowledge-Check generieren\", \"Prüfung schreiben\", \"create the knowledge check\", \"generate a mini-exam\" or \"make the exam for class X\", or asks for exam questions plus solutions from what was actually taught. Do not use for grading submissions (knowledge-assessment) or for assignments in the class folder (homework).","https:\u002F\u002Fgithub.com\u002Fgeorgernstgraf\u002Fopencode-helpers\u002Fblob\u002Fmain\u002Fskills\u002Fknowledge-exam\u002FSKILL.md",[167],{"categoryNo":144,"categoryName":145,"taxonomyType":146,"taxonomyTypeDesc":147},[169,170,151,132,136,23,156,109,171,22,172,173],"exam","knowledge exam","generate","history","german"]