Microsoft Learn Documentation Monitor - How It Works
This guide explains how the automated Microsoft Learn documentation monitoring system works, when it runs, and how to use it locally.
Quick Reference
| Question | Answer |
|---|---|
| When does it run? | Daily at 6:00 AM UTC via GitHub Actions |
| When is a PR created? | Every Sunday (weekly baseline) OR when changes are detected |
| Where are changes stored? | data/monitor-state.json (unified state), reports/monitoring/learn-changes-*.md (reports) |
| How to test locally? | python scripts/learn_monitor.py --dry-run --limit 5 |
System Overview
The Learn monitor tracks ~207 Microsoft Learn URLs from the Microsoft Learn URLs watchlist and detects content changes that may require updates to framework documentation.
Part of Unified Monitoring System: The Learn Monitor is one source adapter within the broader unified monitoring architecture. See monitoring-architecture.md for the complete system design.
+---------------------------------------------------------------------+
| How the Learn Monitor Works |
+---------------------------------------------------------------------+
| |
| 1. WATCHLIST 2. FETCH & HASH |
| +---------------------+ +---------------------+ |
| | microsoft-learn- | --> | For each URL: | |
| | urls.md (209 URLs) | | - Fetch HTML | |
| +---------------------+ | - Extract content | |
| | - Compute SHA-256 | |
| +---------------------+ |
| | |
| v |
| 3. COMPARE 4. CLASSIFY CHANGES |
| +---------------------+ +---------------------+ |
| | data/monitor- | --> | meaningful/minor/ | |
| | state.json (unified)| | noise | |
| | (previous hashes) | +---------------------+ |
| +---------------------+ | |
| v |
| 5. OUTPUT 6. CI TRIGGERS PR |
| +---------------------+ +---------------------+ |
| | reports/monitoring/ | | Exit code 1 OR | |
| | learn-changes-*.md | | Sunday = Create PR | |
| +---------------------+ +---------------------+ |
| |
+---------------------------------------------------------------------+
| Framework: monitoring_shared.py provides state, classification, |
| control mapping, and report generation capabilities |
+---------------------------------------------------------------------+
Key Files
| File | Purpose |
|---|---|
scripts/learn_monitor.py |
Learn Monitor source adapter |
scripts/monitoring_shared.py |
Unified monitoring framework (state, classification, control mapping) |
scripts/regulatory_monitor.py |
Regulatory source adapter (Federal Register, FINRA) |
.github/workflows/learn-monitor.yml |
GitHub Actions workflow for Learn Monitor |
docs/reference/microsoft-learn-urls.md |
Watchlist of 209 URLs to monitor |
data/monitor-state.json |
Unified state file (content hashes for all sources) |
reports/monitoring/learn-changes-*.md |
Learn change reports |
reports/monitoring/regulatory-changes-*.md |
Regulatory change reports |
Change Classification
The monitor classifies changes into categories to prioritize review:
| Classification | Triggers | Priority |
|---|---|---|
| CRITICAL | Affects portal-walkthrough.md playbooks |
Immediate update required |
| HIGH | UI navigation steps, policy language, deprecations | Review and update |
| MEDIUM | General content updates | Review optional |
| NOISE | Metadata, dates, formatting | Ignored |
Patterns Detected as Meaningful
The monitor looks for patterns that indicate substantive changes:
UI Navigation (affects playbooks):
- Navigation keywords:
click,select,go to,navigate - Portal references:
Admin center,portal,Power Platform,Purview - UI elements:
button,menu,tab,panel,dialog,blade
Policy/Compliance (affects controls):
- Callout boxes:
Important:,Warning:,Note:,Caution: - Requirement language:
required,must,should not,prohibited - Compliance terms:
compliance,audit,retention,DLP
Deprecation (requires action):
- Lifecycle terms:
deprecated,removed,no longer,retired - Release stages:
preview,GA,generally available
GitHub Actions Workflow
The workflow (.github/workflows/learn-monitor.yml) runs:
- Schedule: Daily at 6:00 AM UTC (
cron: '0 6 * * *') - Manual: Can be triggered via
workflow_dispatch
PR Creation Logic
IF (today is Sunday) OR (exit_code == 1):
Create PR with changes
ELSE:
No PR (just update state)
Baseline vs. Change Detection Runs
The workflow detects whether this is a baseline run (first successful execution) or a change detection run (subsequent executions):
| Run Type | Condition | PR Body Content |
|---|---|---|
| Baseline | State file doesn't exist before script runs | Explains this establishes the baseline; no change reports expected; simplified 2-step review |
| Change Detection | State file exists | Full instructions to check reports and update affected documentation |
How it works:
# Before running the monitor script:
if [ ! -f "data/learn-monitor-state.json" ]; then
echo "is_baseline=true" # First run
else
echo "is_baseline=false" # Subsequent run
fi
This ensures PR reviewers see appropriate instructions based on the run type.
Exit Codes:
| Code | Meaning | Action |
|---|---|---|
0 |
No meaningful changes detected | No PR created |
1 |
Meaningful changes detected | PR created |
2 |
Error during execution | Check workflow logs |
Testing Locally
1. Quick Test (5 URLs, no state changes)
python scripts/learn_monitor.py --dry-run --limit 5
2. Test with Verbose Output
python scripts/learn_monitor.py --dry-run --limit 10 --verbose
3. Debug a Single URL
python scripts/learn_monitor.py --url "https://learn.microsoft.com/en-us/power-platform/admin/managed-environment-overview"
4. Full Run (creates state file)
# First run establishes baseline (no report generated)
python scripts/learn_monitor.py
# Subsequent runs detect changes
python scripts/learn_monitor.py
Understanding the Output
State File (data/monitor-state.json)
The unified state file stores SHA-256 content hashes for all monitored sources (Learn + Regulatory):
{
"last_updated": "2026-02-04T06:00:00Z",
"sources": {
"learn": {
"urls": {
"https://learn.microsoft.com/...": {
"hash": "sha256:abc123...",
"last_checked": "2026-02-04T06:00:00Z",
"title": "Managed Environments Overview"
}
}
},
"regulatory": { ... }
}
}
Change Reports (reports/monitoring/learn-changes-YYYY-MM-DD.md)
Reports are generated when changes are detected:
- Date and summary of changes
- List of affected URLs with classification
- Diff snippets showing what changed
- Recommended actions for each change
Verifying the Monitor is Working
Option 1: Check GitHub Actions
gh run list --workflow=learn-monitor.yml --limit 5
Option 2: Run Locally
# Dry run (no state changes)
python scripts/learn_monitor.py --dry-run --limit 5 --verbose
# Full baseline run
python scripts/learn_monitor.py --limit 20
Option 3: Check for Recent Reports
ls -la reports/monitoring/learn-changes-*.md
Responding to Change Alerts
When the monitor detects changes and creates a PR:
Option 1: AI-Assisted Review (Recommended)
Use the /review-learn-changes Claude Code skill for automated analysis:
# 1. Checkout the PR branch
gh pr checkout {PR_NUMBER}
# 2. Run the review skill in Claude Code
/review-learn-changes
# 3. Claude will:
# - Read and categorize all changes
# - Propose specific documentation edits
# - Apply edits with your confirmation
# - Run validation (mkdocs build --strict)
# 4. Commit and push the documentation updates
git add .
git commit -m "docs: Apply Learn Monitor updates"
git push
# 5. Merge the PR
gh pr merge {PR_NUMBER} --squash
Option 2: Manual Review
- Review the change report in
reports/monitoring/ - Assess the classification (CRITICAL, HIGH, MEDIUM, NOISE)
- Update affected documentation:
- CRITICAL: Update playbooks immediately
- HIGH: Update controls and playbooks
- MEDIUM: Review and update if needed
- NOISE: No action required
- Merge the PR to update the baseline state
PR Labels
| Label | Meaning |
|---|---|
learn-watch |
All Learn Monitor PRs |
needs-review |
Changes detected that may require documentation updates |
documentation |
Documentation-related PR |
automated |
Created by automation |
End-to-End Verification Procedure
To verify the Learn Monitor works correctly, follow these steps:
Step 1: Establish Baseline (or use existing)
# If no state file exists for Learn URLs, create baseline
python3 scripts/learn_monitor.py --limit 5
# Expected: "Baseline established. No report generated on first run."
# State saved to: data/monitor-state.json (unified state file)
Step 2: Run Again (No Changes Expected)
python3 scripts/learn_monitor.py --limit 5
# Expected: "Meaningful changes: 0" - No report generated
Step 3: Simulate a Content Change
# Inject fake old content to trigger change detection
python3 -c "
import json
with open('data/monitor-state.json', 'r') as f:
state = json.load(f)
first_url = list(state['sources']['learn']['urls'].keys())[0]
state['sources']['learn']['urls'][first_url]['normalized_content'] = 'OLD CONTENT'
state['sources']['learn']['urls'][first_url]['hash'] = 'sha256:fake_hash'
with open('data/monitor-state.json', 'w') as f:
json.dump(state, f, indent=2)
"
# Run monitor - should detect change
python3 scripts/learn_monitor.py --limit 5
# Expected: "CHANGED: meaningful" and report generated
Step 4: Verify Report Created
ls -la reports/monitoring/learn-changes-*.md
cat reports/monitoring/learn-changes-*.md
Step 5: Restore State File
git checkout data/monitor-state.json
rm reports/monitoring/learn-changes-*.md
Verification Summary
| Step | Expected Result |
|---|---|
| Baseline run | "Baseline established. No report generated." |
| No-change run | "Meaningful changes: 0" |
| Simulated change | "CHANGED: meaningful" + report generated |
| Report content | Shows diff, affected controls, priority |
Troubleshooting
| Issue | Cause | Resolution |
|---|---|---|
| No state file exists | Monitor hasn't run yet | Run python scripts/learn_monitor.py to create baseline (stored in unified data/monitor-state.json) |
| URL fetch failures | Network issues or URL changed | Check URL validity, retry later |
| Too many false positives | NOISE detection needs tuning | Review patterns in monitoring_shared.py classification logic |
| Workflow not running | GitHub Actions disabled | Check repository Actions settings |
| State file corrupted | JSON parsing errors | Restore from backup or delete and re-run monitor (establishes new baseline) |
Related Documentation
- Monitoring Architecture: monitoring-architecture.md - Comprehensive unified monitoring system documentation
- AI-Assisted Review: learn-monitor-ai-enhancement.md - AI-assisted review implementation guide
- Microsoft Learn URLs: microsoft-learn-urls.md - The watchlist of monitored URLs (~207 URLs)
- Claude Code Skill:
.claude/skills/review-learn-changes.md- User-invocable skill for reviewing changes - Repository Instructions:
.claude/CLAUDE.md- Complete repository instructions (in project root)
FSI Agent Governance Framework v1.2 - February 2026