opencode-skills-collection 4.0.70 → 4.0.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,181 @@
1
+ ---
2
+ name: marlin-bed-leveling
3
+ description: "Calibrates Marlin 2.x 3D printer firmware bed leveling: Unified Bed Leveling (UBL), Bilinear ABL, M420 S1 post-homing, Z-probe offsets, G26 mesh prints, and EEPROM slots. Trigger phrases: marlin bed leveling, ubl calibration, m420 s1, z probe offset, g29 bed level, first layer adhesion."
4
+ category: development
5
+ risk: safe
6
+ source: community
7
+ source_repo: wwewtech/marlin-bed-leveling
8
+ source_type: community
9
+ date_added: "2026-09-22"
10
+ author: wwewtech
11
+ tags: [3d-printing, marlin-firmware, gcode, hardware-calibration, fdm, additive-manufacturing]
12
+ tools: [claude, cursor, gemini, windsurf]
13
+ license: "MIT"
14
+ ---
15
+
16
+ # Marlin Bed Leveling: Deterministic Calibration & First-Layer Mesh Engineering
17
+
18
+ Master Marlin 2.x bed leveling architectures (Unified Bed Leveling UBL, Bilinear ABL, Manual Mesh MBL) to guarantee flawless first-layer adhesion through rigorous G-code phase workflows, probe offset math, and persistent EEPROM compensation.
19
+
20
+ ## When to Use This Skill
21
+
22
+ Activate this skill when:
23
+ - Calibrating, tuning, or troubleshooting automatic bed leveling on Marlin 2.x 3D printers (Ender 3, CR-10, Prusa clones, custom CoreXY / Cartesian machines).
24
+ - The user asks: "How do I set up UBL in Marlin?", "My printer homes with G28 and ignores the mesh", "Calculate BLTouch Z-probe offset", "Generate G26 validation print G-code", or "Edit warped mesh points with M421".
25
+ - Diagnosing first-layer defects: nozzle dragging across PEI sheets, corner detachment, uneven squish, or compensation disabling after homing.
26
+ - Sizing slicer start G-code sequences (Cura, PrusaSlicer, OrcaSlicer, Bambu Studio) with thermal soaking and mesh restoration.
27
+
28
+ Do NOT use this skill when:
29
+ - Calibrating Klipper or RepRapFirmware printers (different firmware syntax and mesh compensation systems).
30
+ - Fixing gross mechanical skew: loose V-slot rollers, bent Z leadscrews, or wobbly gantry arms (hardware faults cannot be solved by software leveling).
31
+ - Delta printer kinematics setup requiring radius and tower endstop adjustments before mesh probing.
32
+
33
+ ## Core Mental Models & Non-Negotiable Rules
34
+
35
+ 1. **The Post-Homing Enable Mandate (`G28` Disables Leveling)**:
36
+ - In Marlin firmware, executing `G28` (Home All Axes) automatically **DISABLES bed leveling compensation by default** (`RESTORE_LEVELING_AFTER_G28` is often disabled in vendor firmware).
37
+ - In every print start G-code, the leveling restoration command MUST be issued **strictly AFTER `G28`**:
38
+ ```gcode
39
+ G28 ; Home all axes (silently turns leveling OFF)
40
+ M420 S1 ; Re-enable bed leveling compensation from EEPROM mesh
41
+ ```
42
+ - Failing to include `M420 S1` (or `G29 A` for UBL) after `G28` causes the printer to execute the entire print with zero leveling compensation.
43
+
44
+ 2. **The 5-Phase UBL Calibration Loop**:
45
+ Unified Bed Leveling (UBL) is a state machine requiring five sequential phases:
46
+ - **Phase 1 (Probe Reachable Grid)**: `G29 P1` probes all coordinates physically reachable by the probe offset.
47
+ - **Phase 2 (Manual Edge Probing)**: `G29 P2` uses a paper feeler gauge for points the BLTouch cannot reach due to gantry geometry.
48
+ - **Phase 3 (Mathematical Extrapolation)**: `G29 P3 T0.0` fills unprobed edge coordinates by extrapolating slopes from adjacent measured points.
49
+ - **Phase 4 (Validation & Micro-Tuning)**: `G26 B60 H210 F1.75` prints a single-layer validation test pattern; inspect and edit coordinates with `M421 I... J... Q...`.
50
+ - **Phase 5 (Storage & Activation)**: `G29 S1` saves to EEPROM mesh slot 1; `G29 A` activates UBL; `M500` commits to permanent EEPROM storage.
51
+
52
+ 3. **Thermal Equilibrium Pre-Flight Invariant**:
53
+ - Aluminum build plates, magnetic stickers, and spring-steel PEI sheets expand and warp non-linearly under thermal expansion.
54
+ - Probing a bed at room temperature (20°C) and then printing at 60°C or 100°C bakes a $0.08\text{--}0.20\text{mm}$ error into every mesh point.
55
+ - **Mandatory Pre-Flight**: Beds MUST be heated to target operating temperature and soaked for $\ge 5\text{ minutes}$ prior to running `G29` probing.
56
+
57
+ 4. **Z-Probe Offset Sign Convention (`M851 Z...`)**:
58
+ - For downward-deploying probes (BLTouch, CRTouch, inductive sensors) where the probe trigger point triggers *below* the nozzle tip:
59
+ $$\mathbf{Z\text{-}Offset\ is\ strictly\ NEGATIVE}\ (e.g.,\ \text{M851 Z-1.85})$$
60
+ - A *positive* Z-offset on a downward-deploying probe instructs the firmware that the nozzle is lower than the probe trigger, driving the nozzle directly into the bed on the first move.
61
+ - Adjusting Z-offset with paper gauge:
62
+ - More resistance / tighter squish $\implies$ more negative (e.g., `-1.80` $\to$ `-1.85`).
63
+ - Less resistance / looser gap $\implies$ less negative (e.g., `-1.80` $\to$ `-1.75`).
64
+
65
+ 5. **Mesh Fade Height Geometry (`M420 Z...`)**:
66
+ - Leveling compensation must gradually fade out as Z-height increases so top surface layers print geometrically flat rather than conforming to the bed warp.
67
+ - Set fade height to `M420 Z10.0` (fades compensation smoothly over the first 10mm of print height). Setting `Z0` disables fade (perpetuating bed ripples to the top of the model); setting `Z > 25` is unnecessary ballast.
68
+
69
+ ## Named Sins & Anti-Patterns (Что категорически ЗАПРЕЩЕНО)
70
+
71
+ | Anti-Pattern | Manifestation in Code/Workflow | Mandatory Production Counter-Rule |
72
+ | :--- | :--- | :--- |
73
+ | **The Forgotten `M420 S1`** | `G28` followed immediately by print moves. | Always place `M420 S1` (or `G29 A`) immediately after `G28`. |
74
+ | **Cold Bed Mesh Probing** | Running `G29 P1` with bed heater at 20°C. | Heat bed to printing temperature and soak for $\ge 5$ minutes first. |
75
+ | **Positive Z-Probe Offset** | Setting `M851 Z+1.5` on a BLTouch probe. | Downward-deploying probes MUST have a negative Z-offset (`M851 Z-...`). |
76
+ | **Unsaved Mesh Discard** | Probing a 7x7 mesh without running `M500`. | Always commit mesh to EEPROM via `G29 S1` followed by `M500`. |
77
+ | **Software-Fixing Physical Tilt** | Compensating for a 2.5mm physical gantry tilt with UBL. | Physically tram bed corners (`G35` or thumb screws) before probing. |
78
+ | **Blind Unchecked Extrapolation** | Running `G29 P3` without verifying boundary values. | Inspect extrapolated border points with `M420 V` or `G29 T`. |
79
+ | **Cold Extruder G26 Validation** | Running G26 test without nozzle heating. | Heat nozzle to printing temperature (`G26 B60 H210 F1.75`). |
80
+ | **Loose Probe Mount Blindness** | Probing while BLTouch bracket has physical wobble. | Check physical probe mount rigidity; probe repeatability requires $s \le 0.005\text{mm}$ (`M48`). |
81
+ | **Excessive Fade Height** | Setting `M420 Z0` or `M420 Z50`. | Use `M420 Z10.0` to smoothly transition from warped bed to true flat geometry. |
82
+ | **Blind Point Over-Editing** | Manually offsetting a single mesh point by 0.5mm via `M421`. | Clean the build plate or check for debris under PEI sheet before altering matrix. |
83
+
84
+ ## Concrete Archetypes / Presets
85
+
86
+ ### Archetype 1: End-to-End Unified Bed Leveling (UBL) Calibration Macro
87
+ ```gcode
88
+ ; ==============================================================================
89
+ ; MARLIN 2.x UBL FULL CALIBRATION SEQUENCE
90
+ ; ==============================================================================
91
+ M140 S60 ; Start heating bed to 60°C
92
+ M190 S60 ; Wait for bed to reach 60°C
93
+ G4 S300 ; Thermal soak for 300 seconds (5 minutes)
94
+
95
+ G28 ; Home all axes
96
+ M117 Probing Reachable Points...
97
+ G29 P1 ; Phase 1: Automated probe of reachable grid points
98
+
99
+ M117 Extrapolating Mesh Edges...
100
+ G29 P3 T0.0 ; Phase 3: Mathematically extrapolate unprobed perimeter points
101
+ G29 P3 T0.0 ; Second pass to ensure corner fill
102
+
103
+ G29 T ; Print ASCII topology matrix to terminal for verification
104
+ G29 S1 ; Save calibrated mesh to EEPROM slot 1
105
+ G29 A ; Activate UBL leveling system
106
+ M500 ; Save EEPROM permanently to board flash
107
+ M117 UBL Mesh 1 Saved and Activated!
108
+ ```
109
+
110
+ ### Archetype 2: Production Slicer Start G-Code (Cura / PrusaSlicer / Orca)
111
+ ```gcode
112
+ ; ==============================================================================
113
+ ; PRODUCTION SLICER START G-CODE (MARLIN UBL / BILINEAR)
114
+ ; ==============================================================================
115
+ M140 S[first_layer_bed_temperature] ; Start heating bed
116
+ M104 S150 ; Pre-heat nozzle to 150°C (prevent oozing)
117
+ M190 S[first_layer_bed_temperature] ; Wait for bed to stabilize
118
+
119
+ G28 ; Home all axes (turns leveling OFF)
120
+ M420 S1 Z10.0 ; Restore mesh from EEPROM & set 10mm fade
121
+ ; (OR for UBL: G29 A followed by G29 L1)
122
+
123
+ G1 Z50 F3000 ; Move nozzle up to safe clearance
124
+ M109 S[first_layer_temperature] ; Heat nozzle to final printing temp
125
+
126
+ ; Priming Purge Line on bed edge
127
+ G92 E0 ; Reset extruder
128
+ G1 X0.1 Y20 Z0.28 F5000.0 ; Move to start position
129
+ G1 X0.1 Y200.0 Z0.28 F1500.0 E15 ; Draw first purge line
130
+ G1 X0.4 Y200.0 Z0.28 F5000.0 ; Move to side
131
+ G1 X0.4 Y20 Z0.28 F1500.0 E30 ; Draw second purge line
132
+ G92 E0 ; Reset extruder
133
+ G1 Z2.0 F3000 ; Z-hop before moving to print
134
+ ```
135
+
136
+ ### Archetype 3: Probe Repeatability & Offset Verification (`M48` & `M851`)
137
+ ```gcode
138
+ ; ==============================================================================
139
+ ; PROBE REPEATABILITY & Z-OFFSET CALIBRATION
140
+ ; ==============================================================================
141
+ G28 ; Home axes
142
+ G1 X117.5 Y117.5 Z10 F5000 ; Move to center of 235x235 bed
143
+ M48 P10 X117.5 Y117.5 V2 E L2 ; Run 10-point repeatability test
144
+ ; Standard deviation must be <= 0.005 mm. If > 0.010 mm, tighten probe mount!
145
+
146
+ ; Manual Z-Offset adjustment with paper feeler gauge:
147
+ ; 1. Move to Z=0: G1 Z0 F1000
148
+ ; 2. Baby-step Z until paper drags with slight friction
149
+ ; 3. If nozzle moved down 0.15mm: M851 Z-1.85 (subtract 0.15 from current -1.70)
150
+ ; 4. Commit: M500
151
+ ```
152
+
153
+ ## The Pre-Emit Quality Gate Checklist
154
+
155
+ Before emitting any Marlin leveling advice, macro, or slicer start code:
156
+ - [ ] **Post-Homing Verification**: `M420 S1` (or `G29 A`) placed strictly after `G28` in the execution flow.
157
+ - [ ] **Thermal Soak Pre-Flight**: Bed heating and 5-minute soak mandated prior to `G29` probing.
158
+ - [ ] **Negative Offset Math**: Downward-deploying probes have verified negative `M851 Z-...` values.
159
+ - [ ] **EEPROM Commit**: `G29 S1` followed immediately by `M500` to preserve the mesh.
160
+ - [ ] **Fade Height Limit**: `M420 Z10.0` configured for smooth transition to flat geometry.
161
+ - [ ] **Physical Tramming Precedence**: Confirmed that manual corner leveling is performed before software compensation.
162
+ - [ ] **Probe Repeatability**: Confirmed that `M48` probe standard deviation is $\le 0.005\text{mm}$.
163
+
164
+ ## Self-Correction & Verification Loop
165
+
166
+ ### Bad (Vibe-Coded AI Slop Output):
167
+ > "Put `G29` before `G28` in your start G-code. If your BLTouch is scraping, set `M851 Z1.5`. You don't need to heat the bed during leveling because Marlin compensates for it automatically."
168
+ *Problems: Fatal G28 homing wipes out the preceding G29 mesh, positive Z-offset crashes nozzle into bed, dangerous cold probing advice.*
169
+
170
+ ### Good (Production Marlin Bed Leveling Output):
171
+ > 1. Tram the four bed corners manually using `G35` or thumb screws to get mechanical variance under $\pm 0.1\text{mm}$.
172
+ > 2. Heat bed to 60°C and nozzle to 150°C; let soak for 5 minutes so thermal expansion stabilizes.
173
+ > 3. Verify probe repeatability using `M48 P10` (standard deviation must be $\le 0.005\text{mm}$).
174
+ > 4. Probe grid with `G29 P1`, extrapolate unprobed corners with `G29 P3 T0.0`, save to slot 1 with `G29 S1`, and commit to flash with `M500`.
175
+ > 5. In your slicer start G-code, place `M420 S1 Z10.0` immediately after `G28` to restore the active mesh with a 10mm fade height.
176
+
177
+ ## Limitations
178
+
179
+ - Marlin commands and mesh behavior vary with firmware version, configuration, probe, bed geometry, and slicer. Check the exact firmware build and printer documentation before applying a macro or offset.
180
+ - G-code can move a hot toolhead and damage equipment or cause burns. Supervise calibration, keep hands clear, use the printer's emergency stop when motion is unsafe, and verify travel limits before running generated sequences.
181
+ - Example coordinates, temperatures, tolerances, and fade values are illustrative; measure the actual printer and follow the manufacturer’s limits.
@@ -0,0 +1,205 @@
1
+ ---
2
+ name: oneroster-csv-validator
3
+ description: "Validates 1EdTech / IMS Global OneRoster v1.1 and v1.2 CSV roster sets: manifest integrity, bulk vs delta strictness, foreign key references, and encoding sanitization. Trigger phrases: oneroster csv validator, validate oneroster zip, clever roster error, oneroster sourcedid."
4
+ category: testing
5
+ risk: safe
6
+ source: community
7
+ source_repo: wwewtech/oneroster-csv-validator
8
+ source_type: community
9
+ date_added: "2026-09-22"
10
+ author: wwewtech
11
+ tags: [edtech, oneroster, csv-validation, ims-global, 1edtech, data-engineering]
12
+ tools: [claude, cursor, gemini, windsurf]
13
+ license: "MIT"
14
+ ---
15
+
16
+ # OneRoster CSV Validator: Strict 1EdTech Data Integrity & Pre-Flight Linter
17
+
18
+ Perform rigorous pre-flight validation on OneRoster v1.1 and v1.2 CSV roster bundles prior to SIS/Clever/ClassLink ingestion: audit foreign key referential integrity, eliminate orphan enrollments, enforce bulk vs delta partitioning, and sanitize encoding traps.
19
+
20
+ ## When to Use This Skill
21
+
22
+ Activate this skill when:
23
+ - Validating or debugging student information system (SIS) roster export packages (`.zip` archives or CSV directories) for OneRoster v1.1 or v1.2 compliance.
24
+ - The user asks: "Why is Clever rejecting our OneRoster zip file?", "Check for orphaned userSourcedIds in enrollments.csv", "Validate bulk vs delta mode in OneRoster CSVs", or "Sanitize UTF-8 BOM characters from school rosters".
25
+ - Auditing relational integrity across `manifest.csv`, `orgs.csv`, `users.csv`, `courses.csv`, `classes.csv`, `enrollments.csv`, and `academicSessions.csv`.
26
+ - Preparing automated pre-flight CI/CD pipelines to catch corrupted student or teacher records before nightly SIS sync runs.
27
+
28
+ Do NOT use this skill when:
29
+ - Integrating OneRoster REST / OAuth 2.0 API endpoints (this skill focuses strictly on CSV table bindings).
30
+ - Generating synthetic or fabricated student PII without authorization.
31
+ - Working on generic non-standard CSV spreadsheets that do not follow 1EdTech specifications.
32
+
33
+ ## Core Mental Models & Non-Negotiable Rules
34
+
35
+ 1. **The Manifest Root Authority Law**:
36
+ - `manifest.csv` MUST reside strictly at the root level of the ZIP archive (never nested inside a subfolder).
37
+ - It MUST declare the exact specification version: `oneroster.version,1.1` or `oneroster.version,1.2`.
38
+ - It MUST list every single file present in the exchange. If a CSV file is present in the archive but omitted from `manifest.csv`, or listed in `manifest.csv` but missing from the zip, the package is rejected.
39
+
40
+ 2. **The Strict Bulk vs Delta Partition**:
41
+ - One exchange bundle = strictly ONE operational mode.
42
+ - **Bulk Exchange Mode**: Represents a complete master snapshot. In OneRoster 1.1, rows MUST NOT contain `dateLastModified` or `status` columns. In 1.2, all status fields MUST be `active`.
43
+ - **Delta Exchange Mode**: Represents incremental changes. Every row MUST contain a valid ISO 8601 UTC timestamp (`YYYY-MM-DDTHH:MM:SS.sssZ`) in `dateLastModified` and a valid status (`active` or `tobedeleted`).
44
+ - Mixing bulk and delta formats within the same archive is a fatal validation failure.
45
+
46
+ 3. **The Foreign Key Referential Integrity Hierarchy**:
47
+ - Relational dependency chain:
48
+ $$\mathbf{orgs.csv} \longleftarrow \mathbf{courses.csv} \longleftarrow \mathbf{classes.csv} \longleftarrow \mathbf{enrollments.csv} \longrightarrow \mathbf{users.csv}$$
49
+ - Every `schoolSourcedId` in `users.csv` and `classes.csv` MUST resolve to an existing `sourcedId` in `orgs.csv`.
50
+ - Every `courseSourcedId` in `classes.csv` MUST resolve to `courses.csv`.
51
+ - Every `userSourcedId` and `classSourcedId` in `enrollments.csv` MUST resolve to active primary keys in `users.csv` and `classes.csv`.
52
+ - **Zero Orphan Tolerance**: A single orphan link (e.g. enrolling a deleted student ID) invalidates the batch.
53
+
54
+ 4. **Strict Role Enum Constraint Axioms**:
55
+ - In `users.csv`: `role` MUST strictly match the OneRoster enum:
56
+ - v1.1: `administrator`, `proctor`, `student`, `teacher`.
57
+ - v1.2: adds `aide`, `guardian`, `parent`, `staff`.
58
+ - In `enrollments.csv`: `role` is strictly constrained to `administrator`, `proctor`, `student`, `teacher`. Custom vendor roles (`substitute`, `dean`) must be mapped to valid specification enums.
59
+ - Primary `sourcedId` values MUST be case-sensitively unique strings (RFC 4122 UUID format strongly recommended).
60
+
61
+ 5. **RFC 4180 CSV & UTF-8 BOM Sanitization**:
62
+ - Files MUST be encoded in **UTF-8 without Byte Order Mark (BOM)**.
63
+ - Microsoft Excel frequently prepends `\xEF\xBB\xBF` to CSV exports, corrupting the first column name (`sourcedId` $\neq$ `sourcedId`).
64
+ - Fields containing commas, double-quotes, or newlines MUST be enclosed in double quotes (`"`). Literal quotes inside fields must be escaped as `""`.
65
+
66
+ ## Named Sins & Anti-Patterns (Что категорически ЗАПРЕЩЕНО)
67
+
68
+ | Anti-Pattern | Manifestation in CSV Packages | Mandatory Production Counter-Rule |
69
+ | :--- | :--- | :--- |
70
+ | **Nested Archive Packaging** | Zipping a parent folder (`district_roster/manifest.csv`). | Manifest and CSVs MUST reside at the archive root (`/manifest.csv`). |
71
+ | **The UTF-8 BOM Trap** | Excel export injecting `\xEF\xBB\xBF` into `sourcedId`. | Strip BOM headers during pre-flight sanitization pass. |
72
+ | **Orphan Enrollment Links** | `enrollments.csv` pointing to non-existent user IDs. | Enforce foreign key validation across all entity files before import. |
73
+ | **Bulk / Delta Column Bleed** | Including `dateLastModified` or `tobedeleted` in bulk. | Enforce schema separation: bulk files must not contain delta headers. |
74
+ | **Circular Org Hierarchies** | School A listed as parent of School B, and vice-versa. | Perform directed acyclic graph (DAG) cycle detection on `orgs.csv`. |
75
+ | **Illegal Role Strings** | Using non-standard strings like `counselor` or `sub`. | Map all roles to standard enums (`administrator`, `teacher`, `student`). |
76
+ | **Malformed ISO 8601 Timestamps** | Writing `"09/22/2026 14:00"` instead of ISO 8601. | Enforce strict RFC 3339 UTC format: `YYYY-MM-DDTHH:MM:SS.sssZ`. |
77
+ | **Unescaped CSV Commas** | Unquoted commas in user names (`Doe, John`) shifting columns. | Wrap text fields containing commas in standard RFC 4180 quotes. |
78
+ | **Missing Mandatory Core Files** | Exporting a bulk zip without `academicSessions.csv`. | Confirm all 7 mandatory core files exist in zip and manifest. |
79
+ | **Hallucinated SourcedIDs** | Inventing arbitrary IDs during reconciliation. | Preserve authoritative SIS primary keys without synthetic generation. |
80
+
81
+ ## Concrete Archetypes / Presets
82
+
83
+ ### Archetype 1: Pre-Flight Python Referential Integrity Linter
84
+ ```python
85
+ import csv
86
+ import io
87
+ import re
88
+ import zipfile
89
+ from typing import Dict, List, Set
90
+
91
+ CORE_FILES = [
92
+ "manifest.csv", "orgs.csv", "users.csv", "courses.csv",
93
+ "classes.csv", "enrollments.csv", "academicSessions.csv"
94
+ ]
95
+ VALID_ROLES_1_1 = {"administrator", "proctor", "student", "teacher"}
96
+
97
+ def validate_oneroster_archive(zip_path: str) -> dict:
98
+ errors = []
99
+ warnings = []
100
+
101
+ with zipfile.ZipFile(zip_path, 'r') as z:
102
+ names = z.namelist()
103
+
104
+ # 1. Manifest Root Check
105
+ if "manifest.csv" not in names:
106
+ return {"status": "FATAL", "errors": ["manifest.csv missing from zip root."]}
107
+
108
+ # 2. Extract and Parse Core Sets
109
+ data: Dict[str, List[dict]] = {}
110
+ keys: Dict[str, Set[str]] = {}
111
+
112
+ for filename in CORE_FILES:
113
+ if filename in names:
114
+ raw_bytes = z.read(filename)
115
+ # Strip UTF-8 BOM if present
116
+ if raw_bytes.startswith(b'\xef\xbb\xbf'):
117
+ warnings.append(f"{filename} contains UTF-8 BOM; stripped automatically.")
118
+ raw_bytes = raw_bytes[3:]
119
+
120
+ reader = csv.DictReader(io.StringIO(raw_bytes.decode('utf-8', errors='replace')))
121
+ rows = list(reader)
122
+ data[filename] = rows
123
+ if rows and "sourcedId" in rows[0]:
124
+ keys[filename] = {r["sourcedId"] for r in rows if "sourcedId" in r}
125
+ else:
126
+ errors.append(f"Mandatory core file missing: {filename}")
127
+
128
+ # 3. Foreign Key Checks
129
+ if "orgs.csv" in keys and "users.csv" in data:
130
+ for r in data["users.csv"]:
131
+ org_ref = r.get("orgSourcedIds") or r.get("schoolSourcedId")
132
+ if org_ref and org_ref not in keys["orgs.csv"]:
133
+ errors.append(f"users.csv: user {r.get('sourcedId')} references non-existent org {org_ref}")
134
+
135
+ if "users.csv" in keys and "classes.csv" in keys and "enrollments.csv" in data:
136
+ for r in data["enrollments.csv"]:
137
+ uid = r.get("userSourcedId")
138
+ cid = r.get("classSourcedId")
139
+ if uid not in keys["users.csv"]:
140
+ errors.append(f"enrollments.csv: orphan enrollment references missing user {uid}")
141
+ if cid not in keys["classes.csv"]:
142
+ errors.append(f"enrollments.csv: orphan enrollment references missing class {cid}")
143
+
144
+ role = r.get("role")
145
+ if role not in VALID_ROLES_1_1:
146
+ errors.append(f"enrollments.csv: illegal role '{role}' on user {uid}")
147
+
148
+ return {
149
+ "status": "FAILED" if errors else "PASSED",
150
+ "errors": errors,
151
+ "warnings": warnings,
152
+ "total_records_checked": sum(len(v) for v in data.values())
153
+ }
154
+ ```
155
+
156
+ ### Archetype 2: Minimal Valid OneRoster v1.1 Manifest
157
+ ```csv
158
+ propertyName,value
159
+ oneroster.version,1.1
160
+ file.orgs,bulk
161
+ file.users,bulk
162
+ file.courses,bulk
163
+ file.classes,bulk
164
+ file.enrollments,bulk
165
+ file.academicSessions,bulk
166
+ ```
167
+
168
+ ### Archetype 3: Delta Synchronization Row Example
169
+ ```csv
170
+ sourcedId,status,dateLastModified,userSourcedId,classSourcedId,role,primary
171
+ enr_99201,active,2026-09-22T08:30:00.000Z,usr_0421,cls_bio101,student,true
172
+ enr_99202,tobedeleted,2026-09-22T08:30:00.000Z,usr_0884,cls_bio101,student,false
173
+ ```
174
+
175
+ ## The Pre-Emit Quality Gate Checklist
176
+
177
+ Before emitting validation results, CSV transforms, or roster scripts:
178
+ - [ ] **Root Location**: Confirmed `manifest.csv` is located strictly at `/` without folder nesting.
179
+ - [ ] **BOM Scrubbing**: Verified all CSV headers are clean UTF-8 without `\xEF\xBB\xBF`.
180
+ - [ ] **Mode Consistency**: Verified no delta columns exist in bulk packages, and timestamps exist in deltas.
181
+ - [ ] **Referential Integrity**: 100% check of `userSourcedId`, `classSourcedId`, `orgSourcedIds`, and `courseSourcedId`.
182
+ - [ ] **Role Enum Validation**: Confirmed all role values match 1EdTech specifications.
183
+ - [ ] **Cycle-Free Orgs**: DAG validation run on `orgs.csv` to ensure no circular parent references.
184
+ - [ ] **RFC 4180 Escaping**: Commas, quotes, and multi-line values enclosed in double quotes.
185
+
186
+ ## Self-Correction & Verification Loop
187
+
188
+ ### Bad (Vibe-Coded AI Slop Output):
189
+ > "Zip your CSV folder up and upload it. If Clever says there is a missing manifest, just add a blank manifest.csv inside the folder. If some student IDs are missing in enrollments, just delete those rows or invent temporary user IDs."
190
+ *Problems: Nested zip breaks root discovery, blank manifest violates schema, inventing fake IDs corrupts student records, ignores UTF-8 BOM.*
191
+
192
+ ### Good (Production OneRoster CSV Validator Output):
193
+ > 1. Extract zip to verify `/manifest.csv` exists at the root path; confirm `oneroster.version` is declared as `1.1`.
194
+ > 2. Scan all CSV headers: detect and strip UTF-8 BOM (`\xEF\xBB\xBF`) from `users.csv` to prevent header corruption.
195
+ > 3. Perform foreign key referential integrity pass:
196
+ > - Flag 4 orphan rows in `enrollments.csv` referencing deleted student ID `usr_9914`.
197
+ > - Flag invalid role `"substitute_teacher"` on row 14 of `enrollments.csv` (must map to `"teacher"`).
198
+ > 4. Verify bulk purity: confirm no `dateLastModified` or `tobedeleted` status flags are present in bulk mode.
199
+ > 5. Emit clean, line-numbered pre-flight audit report before committing to SIS ingestion.
200
+
201
+ ## Limitations
202
+
203
+ - OneRoster version details and required files can differ by exchange profile and vendor implementation. Validate against the exact 1EdTech specification and recipient's current import contract before rejecting or transforming a roster.
204
+ - Student and staff roster files contain sensitive education records. Process only with authorization, minimize retained data, redact identifiers in diagnostics, and do not upload source CSVs to external services.
205
+ - The included snippets are illustrative, not a complete certified validator; for example, large files, namespaces, delta semantics, and vendor extensions require additional handling and tests.
@@ -172,9 +172,35 @@ Making money from Mini Apps
172
172
  | TON payments | Premium features | High |
173
173
  | In-app purchases | Virtual goods | High |
174
174
  | Ads (Telegram Ads) | Display ads | Medium |
175
+ | In-app ad networks (e.g. TADS) | Native / fullscreen / rewarded ads inside the Mini App | Medium |
175
176
  | Referral | Share to earn | Medium |
176
177
  | NFT sales | Digital collectibles | High |
177
178
 
179
+ ### In-app ads (rewarded and native)
180
+
181
+ Ad networks built for Mini Apps serve ads inside the app itself, so you keep the user in the flow and can reward them (extra life, coins) for a click or a full view. Example with [TADS](https://tads.me) (`npm install react-tads-widget`):
182
+
183
+ ```jsx
184
+ import { TadsWidgetProvider, TadsWidget } from 'react-tads-widget';
185
+
186
+ // wrap the app once
187
+ <TadsWidgetProvider><App /></TadsWidgetProvider>
188
+
189
+ // native block inside content; onClickReward makes it a rewarded ad
190
+ <TadsWidget id="YOUR_WIDGET_ID" type="static"
191
+ onClickReward={() => grantBonus()}
192
+ onAdsNotFound={() => hidePlaceholder()} />
193
+ ```
194
+
195
+ Fullscreen ads work the same way with `type="fullscreen"` and `onShowReward`; show them on a user action, never on load. Agent-readable docs: https://tads.me/llms.txt
196
+
197
+ #### Advertising safety and limitations
198
+
199
+ - Confirm the network, widget format, reward rules, Telegram requirements, and applicable privacy obligations for the app and audience before deployment. Tell users when content is an ad and what action earns a reward.
200
+ - Treat click/show callbacks as client-side UI signals only. Do not use them alone to grant transferable or purchasable value; validate reward events with a trusted server-side source where available, and make grants idempotent and abuse-resistant.
201
+ - Keep ad display optional and user-initiated where the format calls for it. Never show a fullscreen ad automatically on app load or make an ad interaction the only way to use a core feature.
202
+ - SDK APIs and publisher terms can change. Check the current TADS documentation and package version before copying examples into production.
203
+
178
204
  ### Telegram Stars (New!)
179
205
  ```javascript
180
206
  // In your bot
@@ -434,7 +434,8 @@ def format_markdown(design_system: dict) -> str:
434
434
  # Anti-patterns section
435
435
  if anti_patterns:
436
436
  lines.append("### Avoid (Anti-patterns)")
437
- lines.append(f"- {anti_patterns.replace(' + ', '\n- ')}")
437
+ anti_bullets = "- " + anti_patterns.replace(' + ', '\n- ')
438
+ lines.append(anti_bullets)
438
439
  lines.append("")
439
440
 
440
441
  # Pre-Delivery Checklist section
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-skills-collection",
3
- "version": "4.0.70",
3
+ "version": "4.0.72",
4
4
  "description": "OpenCode CLI plugin that automatically downloads and keeps skills up to date.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",