Skip to content

Commit 0824065

Browse files
savvidesphilippos savvidesclaude
authored
feat: imported-course mode for needs-analysis, assessment-design, course-builder (#9)
* feat: imported-course mode for needs-analysis, assessment-design, course-builder Three skills assumed net-new course design and broke down for imported courses (TMC-430 test report issues #7, #13, #14). Each now branches early on import_metadata.source: - needs-analysis: skips the "is training the right intervention?" decision gate for credit-bearing imports (the registrar can't be told to remove the course); records justification automatically and runs a design-fit check. - assessment-design: adds Mode 3 (Audit Existing Assessments) alongside the existing Mode 1/Mode 2 split. Reads existing rubrics, classifies on Bloom's, compares to ILOs, surfaces alignment gaps. Does NOT propose new assessments unless asked. Mode 3 takes precedence over Mode 1. - course-builder: adds gap-fill mode triggered when import_metadata.source is set and course_content.modules is non-empty. Generates ONLY artifacts upstream skills flagged as missing, instead of regenerating syllabus, modules, and rubrics that already exist in the cartridge. All three skills announce the chosen mode at the start of the conversation, so the user can override if auto-detection is wrong. Canonical schema gains optional needs_analysis.mode, assessments.mode, course_content.mode (record the mode), assessments.audit_notes[] (Mode 3 output), and course_content.recommended_generation_targets[] (gap-fill output). Additive — no schema version bump. assessment-design also switches its manifest write to bin/idstack-manifest-merge (landed in v2.1.0.0), eliminating the misleading "include the COMPLETE schema structure" instruction. Smoke test grows from 150 to 153 assertions: each mode-aware skill template must reference import_metadata.source (drift guard). Resolves test-report issues #7, #13, #14. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: address Gemini code review findings on PR #9 Two corrections from Gemini Code Assist's review of this PR: - assessment-design: the manifest-write text said "writes two sections — assessments and learning_objectives.alignment_matrix.ilo_to_assessment" but the merge tool operates on top-level sections only, and Mode 3 also writes to learning_objectives.alignment_matrix.gaps. Clarified to "writes two top-level sections — assessments and learning_objectives" with a note about reading-then-merging the full learning_objectives section before passing it to the merge tool. - course-builder: gap-fill mode instructions referenced course_builder_notes.recommended_generation_targets and course_builder_notes.mode, but the canonical schema (and the course_content.generated_files reference in the same sentence) puts these under course_content. Real bug — Claude following the skill would write to a section that isn't whitelisted by bin/idstack-manifest-merge. Renamed both to course_content. Smoke test 153/153 unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: philippos savvides <philippossavvides@mac.lan> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ee39d74 commit 0824065

15 files changed

Lines changed: 632 additions & 48 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## v2.3.0.0 (2026-05-02)
4+
5+
### Added
6+
- **Imported-course mode for `needs-analysis`, `assessment-design`, and `course-builder`.** The TMC-430 test report flagged that these skills assume net-new course design and break down for imported courses. Each now branches early on `import_metadata.source`:
7+
- `needs-analysis` skips the "is training the right intervention?" decision gate for credit-bearing imports (the registrar can't be told to remove the course); records the rationale and confidence automatically and runs a "design-fit" check instead.
8+
- `assessment-design` adds **Mode 3: Audit Existing Assessments** alongside the existing Mode 1/Mode 2 split. Reads the existing rubrics from the cartridge, classifies criteria on Bloom's, compares to ILOs, and surfaces alignment gaps — does NOT propose new assessments unless the user explicitly asks. Mode 3 takes precedence over Mode 1.
9+
- `course-builder` adds **gap-fill mode** triggered when `import_metadata.source` is set and `course_content.modules` is non-empty. Generates ONLY the artifacts upstream skills flagged as missing (e.g., a missing rubric, a formative practice quiz set), instead of regenerating the syllabus, modules, and rubrics that already exist in the cartridge.
10+
- All three skills announce the chosen mode at the start of the conversation so the user can override if the auto-detection is wrong.
11+
- Resolves test-report issues #7, #13, #14.
12+
- **Canonical schema additions** (additive, no version bump): optional `needs_analysis.mode`, `assessments.mode`, `course_content.mode` (record which mode the skill ran in); `assessments.audit_notes[]` (Mode 3 outputs); `course_content.recommended_generation_targets[]` (gap-fill mode outputs). Per-section item shapes documented in `templates/manifest-schema.md`.
13+
- **`assessment-design` switches to `bin/idstack-manifest-merge`.** Replaces the inline-write pattern (with its misleading "Include the COMPLETE schema structure" instruction) with two scoped merge calls — one for `assessments`, one for `learning_objectives`. Same atomic-write benefits introduced in v2.1.0.0.
14+
15+
### Changed
16+
- Smoke test now runs 153 assertions (was 150). New: each of the 3 mode-aware skill templates must reference `import_metadata.source` (drift guard against accidental removal of the mode-detection branch).
17+
318
## v2.2.0.1 (2026-05-02)
419

520
### Fixed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.2.0.1
1+
2.3.0.0

skills/accessibility-review/SKILL.md

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ The merge tool replaces only the named top-level section, preserves every other
597597
"available_tech": []
598598
},
599599
"needs_analysis": {
600+
"mode": "",
600601
"organizational_context": {
601602
"problem_statement": "",
602603
"stakeholders": [],
@@ -633,6 +634,7 @@ The merge tool replaces only the named top-level section, preserves every other
633634
"expertise_reversal_flags": []
634635
},
635636
"assessments": {
637+
"mode": "",
636638
"assessment_strategy": "",
637639
"items": [],
638640
"formative_checkpoints": [],
@@ -642,9 +644,11 @@ The merge tool replaces only the named top-level section, preserves every other
642644
"peer_review": false
643645
},
644646
"feedback_quality_score": 0,
645-
"rubrics": []
647+
"rubrics": [],
648+
"audit_notes": []
646649
},
647650
"course_content": {
651+
"mode": "",
648652
"generated_at": "",
649653
"expertise_adaptation": "",
650654
"syllabus": "",
@@ -654,7 +658,8 @@ The merge tool replaces only the named top-level section, preserves every other
654658
"content_dir": ".idstack/course-content/",
655659
"generated_files": [],
656660
"build_timestamp": "",
657-
"placeholders_used": []
661+
"placeholders_used": [],
662+
"recommended_generation_targets": []
658663
},
659664
"import_metadata": {
660665
"source": "",
@@ -876,6 +881,37 @@ These document the **shape of array elements and dictionary values** that the ca
876881
}
877882
```
878883

884+
### Mode field — design-new vs audit-existing
885+
886+
`needs_analysis.mode`, `assessments.mode`, and `course_content.mode` record which operating mode the corresponding skill ran in. Trigger: `import_metadata.source``{cartridge, scorm, canvas-api}` plus the relevant section being non-empty (skill-specific check).
887+
888+
Allowed values per skill:
889+
- `needs_analysis.mode`: `"design-new"` or `"audit-existing"`
890+
- `assessments.mode`: `"Mode 1"`, `"Mode 2"`, or `"Mode 3"` (Mode 1 = full upstream data, Mode 2 = ILOs-from-scratch, Mode 3 = audit existing assessments)
891+
- `course_content.mode`: `"build-new"` or `"gap-fill"`
892+
893+
Empty string means the skill hasn't run yet or didn't record the mode (legacy manifests).
894+
895+
**`assessments.audit_notes[]`** — only populated in Mode 3. Records which audit findings the user chose to act on:
896+
```json
897+
{
898+
"target_id": "A-3",
899+
"action": "applied|deferred|declined",
900+
"description": "Rubric criterion for ILO-2 added: 'Synthesis depth (1-4 scale)'.",
901+
"reason": "Optional — only meaningful for deferred/declined."
902+
}
903+
```
904+
905+
**`course_content.recommended_generation_targets[]`** — populated in `gap-fill` mode. Lists artifacts upstream skills flagged as missing, with status:
906+
```json
907+
{
908+
"description": "Discussion rubric for Module 5",
909+
"source": "red-team:alignment-3 | quality-review:learner_support-2 | user-request",
910+
"status": "generated|deferred|declined",
911+
"output_path": "Optional — set when status=generated, points to the generated file."
912+
}
913+
```
914+
879915
## Feedback
880916

881917
Have feedback or a feature request? [Share it here](https://forms.gle/6LDgDD1M6WWyYvME8) — no GitHub account needed.

skills/assessment-design/SKILL.md

Lines changed: 96 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ fi
317317

318318
## Pipeline Context Check
319319

320-
Determine your operating mode based on available data.
320+
Determine your operating mode based on available data. **Check Mode 3 first** — it's the more specific case (imported course with existing assessments) and takes precedence over Mode 1 even when both conditions hold.
321321

322322
### Mode 1: Full Upstream Data
323323

@@ -355,6 +355,38 @@ cognitive process) before proceeding to assessment design. Use the same classifi
355355
approach as the `/learning-objectives` skill: ask for clarification when verbs are
356356
ambiguous [Alignment-12] [T2].
357357

358+
### Mode 3: Audit Existing Assessments
359+
360+
**Condition (BOTH must be true):**
361+
- `import_metadata.source` is one of `cartridge`, `scorm`, `canvas-api`
362+
- `assessments.items` is non-empty (course-import populated it) OR `course_content.assessments` is non-empty (cartridge has assessment artifacts)
363+
364+
**Announce the chosen mode to the user as the first sentence:**
365+
366+
> "Mode 3: audit-existing. The imported course already contains [N] assessments and [M] rubrics — I'll audit them against your ILOs rather than designing new ones from scratch. If you want to add new assessments, say 'design more' at any point."
367+
368+
**What audit-existing does (and doesn't do):**
369+
370+
- ✅ Reads existing rubrics from the manifest (`assessments.rubrics`) or from the cartridge files referenced by `course_content.rubrics`.
371+
- ✅ Classifies each rubric criterion on Bloom's level (same classification approach as Mode 1).
372+
- ✅ Compares to the course ILOs from `learning_objectives.ilos`. Flags:
373+
- **Bloom's level mismatch** — rubric tests below the ILO's claimed level (e.g., ILO says "analyze" but rubric criteria are "list/describe").
374+
- **Untested ILOs** — an ILO has no rubric criterion measuring it.
375+
- **Orphaned criteria** — a rubric criterion doesn't measure any stated ILO.
376+
- **Missing rubric** — an assessment has weight ≥10% but no rubric.
377+
- **No elaborated feedback** — auto-graded MCQ-only assessments without elaborated feedback opportunities. [Assessment-8] [T1]
378+
- ✅ Output: an audit table per assessment, plus 1-3 rubric-improvement recommendations.
379+
- ❌ Does NOT generate new rubrics or new assessments unless the user explicitly says "design more."
380+
381+
**Audit workflow steps (replaces Steps 1-4 of the design workflow below):**
382+
383+
1. **Inventory.** List every assessment from `assessments.items` (or derived from cartridge if items is empty). Note type, title, weight, ILOs claimed.
384+
2. **Per-assessment Bloom's mapping.** For each assessment, examine its rubric criteria and classify each on Bloom's. Record in `assessments.items[].alignment_status` (`"weak" | "moderate" | "strong"` per the canonical schema) based on whether the criteria collectively reach the ILO's claimed level.
385+
3. **Cross-walk.** Build a `learning_objectives.alignment_matrix.gaps[]` entries for each Bloom-mismatch, untested ILO, or orphaned criterion. Use the canonical `gaps[]` shape: `{ilo, type, description, severity}`.
386+
4. **Recommendations.** Surface the top 1-3 fixes — usually rubric criterion edits, not new assessments. If the user wants to act on them, propose specific edits and apply via `Edit`. Track applied/deferred fixes in a new optional `assessments.audit_notes` array.
387+
388+
When done, write the manifest using `bin/idstack-manifest-merge` (see "Write Manifest" below). Skip the rest of this skill (Steps 1-4 of the design workflow are for design-new mode only).
389+
358390
---
359391

360392
## Assessment Design Workflow
@@ -593,19 +625,32 @@ Consider adding a formative peer review checkpoint to partially address the gap.
593625

594626
## Write Manifest
595627

596-
Create or update the project manifest at `.idstack/project.json`.
628+
Save results to `.idstack/project.json` via `bin/idstack-manifest-merge`. The merge tool
629+
replaces only the named section, preserves every other section verbatim, validates JSON,
630+
and atomically updates the top-level `updated` timestamp. **This skill writes two
631+
top-level sections**`assessments` and `learning_objectives` — so call the merge tool
632+
twice (once per section). The `learning_objectives` write needs to update the
633+
`alignment_matrix.ilo_to_assessment` mapping (and in Mode 3, the
634+
`alignment_matrix.gaps` array as well). Read the existing `learning_objectives` section
635+
first, merge in your changes, then pass the full updated section as the payload.
597636

598-
**CRITICAL — Manifest Integrity Rules:**
599-
1. If a manifest already exists, READ it first with the Read tool. Then modify ONLY
600-
the `assessments` section and the `learning_objectives.alignment_matrix.ilo_to_assessment`
601-
mapping. Preserve all other sections unchanged.
602-
2. Include the COMPLETE schema structure. Do not omit fields.
603-
3. Before writing, mentally verify the JSON is valid: matching braces, proper commas,
604-
quoted strings, no trailing commas.
605-
4. The `updated` timestamp must reflect the current time.
606-
5. If this is a new manifest (no needs analysis or learning objectives were run),
607-
initialize ALL sections with empty/default values so downstream skills find the
608-
expected structure.
637+
```bash
638+
# Section 1: assessments
639+
"$_IDSTACK/bin/idstack-manifest-merge" --section assessments --payload - <<'PAYLOAD'
640+
<the assessments payload — see field shape below>
641+
PAYLOAD
642+
643+
# Section 2: learning_objectives (full section, with updated alignment_matrix)
644+
# Read existing learning_objectives, merge in the new ilo_to_assessment mapping
645+
# (and in Mode 3, the new gaps[] entries), then pass the full updated section here.
646+
"$_IDSTACK/bin/idstack-manifest-merge" --section learning_objectives --payload - <<'PAYLOAD'
647+
<the merged learning_objectives payload>
648+
PAYLOAD
649+
```
650+
651+
If `bin/idstack-manifest-merge` is unavailable: fall back to manual write (Read manifest, modify only the two sections, Write back, preserve all others).
652+
653+
If `.idstack/project.json` does not exist yet, run `bin/idstack-migrate .idstack/project.json` first — that creates a fresh canonical manifest. The merge tool then merges into it.
609654

610655
**Populate the `assessments` section:**
611656

@@ -746,6 +791,7 @@ The merge tool replaces only the named top-level section, preserves every other
746791
"available_tech": []
747792
},
748793
"needs_analysis": {
794+
"mode": "",
749795
"organizational_context": {
750796
"problem_statement": "",
751797
"stakeholders": [],
@@ -782,6 +828,7 @@ The merge tool replaces only the named top-level section, preserves every other
782828
"expertise_reversal_flags": []
783829
},
784830
"assessments": {
831+
"mode": "",
785832
"assessment_strategy": "",
786833
"items": [],
787834
"formative_checkpoints": [],
@@ -791,9 +838,11 @@ The merge tool replaces only the named top-level section, preserves every other
791838
"peer_review": false
792839
},
793840
"feedback_quality_score": 0,
794-
"rubrics": []
841+
"rubrics": [],
842+
"audit_notes": []
795843
},
796844
"course_content": {
845+
"mode": "",
797846
"generated_at": "",
798847
"expertise_adaptation": "",
799848
"syllabus": "",
@@ -803,7 +852,8 @@ The merge tool replaces only the named top-level section, preserves every other
803852
"content_dir": ".idstack/course-content/",
804853
"generated_files": [],
805854
"build_timestamp": "",
806-
"placeholders_used": []
855+
"placeholders_used": [],
856+
"recommended_generation_targets": []
807857
},
808858
"import_metadata": {
809859
"source": "",
@@ -1025,6 +1075,37 @@ These document the **shape of array elements and dictionary values** that the ca
10251075
}
10261076
```
10271077

1078+
### Mode field — design-new vs audit-existing
1079+
1080+
`needs_analysis.mode`, `assessments.mode`, and `course_content.mode` record which operating mode the corresponding skill ran in. Trigger: `import_metadata.source``{cartridge, scorm, canvas-api}` plus the relevant section being non-empty (skill-specific check).
1081+
1082+
Allowed values per skill:
1083+
- `needs_analysis.mode`: `"design-new"` or `"audit-existing"`
1084+
- `assessments.mode`: `"Mode 1"`, `"Mode 2"`, or `"Mode 3"` (Mode 1 = full upstream data, Mode 2 = ILOs-from-scratch, Mode 3 = audit existing assessments)
1085+
- `course_content.mode`: `"build-new"` or `"gap-fill"`
1086+
1087+
Empty string means the skill hasn't run yet or didn't record the mode (legacy manifests).
1088+
1089+
**`assessments.audit_notes[]`** — only populated in Mode 3. Records which audit findings the user chose to act on:
1090+
```json
1091+
{
1092+
"target_id": "A-3",
1093+
"action": "applied|deferred|declined",
1094+
"description": "Rubric criterion for ILO-2 added: 'Synthesis depth (1-4 scale)'.",
1095+
"reason": "Optional — only meaningful for deferred/declined."
1096+
}
1097+
```
1098+
1099+
**`course_content.recommended_generation_targets[]`** — populated in `gap-fill` mode. Lists artifacts upstream skills flagged as missing, with status:
1100+
```json
1101+
{
1102+
"description": "Discussion rubric for Module 5",
1103+
"source": "red-team:alignment-3 | quality-review:learner_support-2 | user-request",
1104+
"status": "generated|deferred|declined",
1105+
"output_path": "Optional — set when status=generated, points to the generated file."
1106+
}
1107+
```
1108+
10281109
## Feedback
10291110

10301111
Have feedback or a feature request? [Share it here](https://forms.gle/6LDgDD1M6WWyYvME8) — no GitHub account needed.

0 commit comments

Comments
 (0)