Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ output/
renders/
!packages/producer/tests/*/output/
!packages/producer/tests/distributed/*/output/
# Learn companion-video projects live under learn/output/<slug>/ and MUST be
# tracked (script, scenes, assembled index). The blanket output/ rule above
# would otherwise hide every new body scene from git.
!learn/output/
!learn/output/**
# Never commit licensed Segoe WOFF2 stand-ins dropped into a project fonts/.
learn/output/**/fonts/*.woff2
learn/output/**/fonts/fonts.css
# Source dir that the renders/ output rule accidentally shadows (its files are
# tracked; without this, pre-commit's format re-stage fails on them).
!packages/studio/src/components/renders/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Bulk Identity Management with Graph PowerShell

- **Profile:** `unit-video` — Unit video (~4 min)
- **Target:** ~240s content (180–300s), word budget 435–726 (target 580) @ 2.42 w/s
- **Scenes:** aim ~10 (chrome 5 stamped + ~5-16 body)
- **Max static hold:** 5.0s · **Voice:** en-US-Ava:DragonHDLatestNeural
- **Source:** C:\learn-pr\learn-m365-pr\learn-m365-pr\wwl\provision-govern-identities-entra\includes\3-bulk-identity-management-graph.md

## Fill the placeholders

Every `__FILL__` below must be replaced before render (guarded by `tools/check_placeholders.py`).

- `opening.bumper` → [scenes/01-bumper.html](scenes/01-bumper.html)
- `opening.title` → [scenes/02-title.html](scenes/02-title.html)
- `opening.objectives` → [scenes/03-objectives.html](scenes/03-objectives.html)
- `closing.recap` → [scenes/90-recap.html](scenes/90-recap.html)
- `closing.cta` → [scenes/91-cta.html](scenes/91-cta.html)

## Next steps

1. Write the script + beat plan (script-writer) and fill the chrome placeholders above.
2. Author the teaching-body scenes into `scenes/` and insert them into `scenes.json` between the opening and closing chrome (see `scenes.json` → `body_slot`).
3. Run the gated pipeline (voice → fact-check QA → build → snapshot QA → render).
4. Guard: `py tools/check_placeholders.py --project .` must be clean before render.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// GENERATED by tools/word_anchors.py - do not hand-edit.
// Every value is a REAL spoken-word time from transcript.json,
// with a 3.0s lead-in applied. Regenerate after any re-record.
window.__anchors = {
"connect_cmd": 57.32,
"connect_cmdEnd": 58.97,
"connect_scope": 68.08,
"connect_scopeEnd": 71.31,
"contacts_trap": 218.54,
"contacts_trapEnd": 220.43,
"create_newmguser": 109.12,
"create_newmguserEnd": 110.25,
"csv_columns": 92.67,
"csv_columnsEnd": 96.44,
"cta_exercise": 258.23,
"cta_exerciseEnd": 260.18,
"hook_question": 17.67,
"hook_questionEnd": 20.35,
"import_csv": 80.12,
"import_csvEnd": 82.81,
"least_privilege": 156.94,
"least_privilegeEnd": 158.61,
"loop_count30": 121.21,
"loop_count30End": 122.31,
"loop_creates": 113.37,
"loop_createsEnd": 116.76,
"loop_enabled": 116.79,
"loop_enabledEnd": 117.75,
"loop_forcepw": 117.75,
"loop_forcepwEnd": 119.65,
"loop_foreach": 104.39,
"loop_foreachEnd": 106.72,
"match_scope_question": 143.74,
"match_scope_questionEnd": 145.28,
"newmailcontact": 228.37,
"newmailcontactEnd": 229.64,
"objectives_scope": 31.86,
"objectives_scopeEnd": 33.68,
"overview_steps": 53.38,
"overview_stepsEnd": 55.33,
"pattern_scales": 162.94,
"pattern_scalesEnd": 165.38,
"read_scope": 165.38,
"read_scopeEnd": 167.25,
"recap_one_pass": 242.52,
"recap_one_passEnd": 244.73,
"remove_cmd": 205.97,
"remove_cmdEnd": 207.63,
"repeatable": 127.28,
"repeatableEnd": 129.19,
"update_cmd": 198.74,
"update_cmdEnd": 200.2
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"_schema": "cue id -> exact spoken phrase (contiguous, case/punctuation-insensitive substring of narration.txt). Builder resolves to real times: py tools/word_anchors.py transcript.json --spec anchors.json -o anchors.js --lead-in <n>",
"_builder_note": "overview_steps was respoken/transcribed as \"Connect, loop\" (the TTS elided \"import\"); the phrase is bound to what the WAV actually says so the lock-up lands on the real word. loop_* cues added by the builder for the custom 07-loop console.",
"_note": "Phrases intentionally land on ORDINARY words next to each cmdlet/scope token, never the token itself — how 'New-MgUser' / 'User.ReadWrite.All' tokenize in the transcript is unpredictable, so anchoring on plain words is robust. Each phrase is unique; if the TTS re-run makes one ambiguous, append '#2' to pick an occurrence.",
"_run_id": "bulk-identity-management-graph-202608071310",

"hook_question": "how do you create every one of those accounts",
"objectives_scope": "the right permission scope",

"overview_steps": "Connect, loop",

"connect_cmd": "session starts with",
"connect_scope": "you ask for exactly one scope",

"import_csv": "reads your spreadsheet into a collection",
"csv_columns": "a display name, a user principal name",

"loop_foreach": "Now the loop does the work",
"create_newmguser": "hands each row to",
"loop_creates": "creates the account",
"loop_enabled": "switches it on",
"loop_forcepw": "and forces a password reset",
"loop_count30": "30 rows in",

"repeatable": "A script is repeatable",

"match_scope_question": "and not the broader",
"least_privilege": "match the scope to the task",

"pattern_scales": "scales to every bulk job",
"read_scope": "Reading users for an audit",

"update_cmd": "runs the very same",
"remove_cmd": "when an account has to go",

"contacts_trap": "doesn't manage mail contacts",
"newmailcontact": "That job belongs to",

"recap_one_pass": "the whole roster in one pass",
"cta_exercise": "The next exercise takes you"
}
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Large diffs are not rendered by default.

Loading