Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
bd4b2f2
Add startup hub context and explicit routing
MajorIncident Oct 8, 2026
5550f2c
Route ordinary startup through explicit hub
MajorIncident Oct 8, 2026
a9f30f8
Turn experience chooser into startup hub
MajorIncident Oct 8, 2026
ff84ef0
Use Run a class product language
MajorIncident Oct 8, 2026
a565758
Focus startup resume before new-session choices
MajorIncident Oct 8, 2026
38e7381
Return invalid Student resumes to startup hub
MajorIncident Oct 8, 2026
b92e052
Return invalid Instructor resumes to startup hub
MajorIncident Oct 8, 2026
c7ff645
Wire startup hub into boot and resume recovery
MajorIncident Oct 8, 2026
ae49d89
Style responsive startup experience hub
MajorIncident Oct 8, 2026
541af1e
Test startup hub resume detection
MajorIncident Oct 8, 2026
59001aa
Update experience-role tests for explicit startup
MajorIncident Oct 8, 2026
ffaf173
Cover explicit startup hub choices
MajorIncident Oct 8, 2026
2622157
Require explicit Continue for saved Standalone Intake
MajorIncident Oct 8, 2026
5abfdc4
Require explicit Rejoin for Student resume
MajorIncident Oct 8, 2026
5156d23
Require explicit Continue for Instructor resume
MajorIncident Oct 8, 2026
e836136
Keep expired Student resume out of startup choices
MajorIncident Oct 8, 2026
6d4795a
Route share links through explicit startup Join
MajorIncident Oct 8, 2026
b24b056
Expect Run a class startup wording
MajorIncident Oct 8, 2026
72e86c1
Test Run a class role label
MajorIncident Oct 8, 2026
da0c1b2
Mark dynamic startup controls local-only
MajorIncident Oct 8, 2026
38d2c84
Honor reduced motion in startup hub
MajorIncident Oct 8, 2026
b2a29f9
Validate fresh startup hub on desktop and mobile
MajorIncident Oct 8, 2026
b447e6e
Document explicit startup hub behavior
MajorIncident Oct 8, 2026
16c8f4a
Map explicit startup intent architecture
MajorIncident Oct 8, 2026
7f64aab
Advance hardening plan to startup hub
MajorIncident Oct 8, 2026
3b09f6b
Advance roadmap to active startup hub
MajorIncident Oct 8, 2026
b5faa85
Checkpoint active startup hub work
MajorIncident Oct 8, 2026
bf7ef68
Document startup hub boot contract
MajorIncident Oct 8, 2026
84b7cd8
Register startup hub feature contract
MajorIncident Oct 8, 2026
5a2af44
Add startup hub markup guardrails
MajorIncident Oct 8, 2026
1b5d1fc
Activate Student explicitly in Classroom feature harness
MajorIncident Oct 8, 2026
7b3125f
Activate Instructor explicitly in Classroom feature harness
MajorIncident Oct 8, 2026
1cc0d08
Activate Standalone explicitly in resource feature harness
MajorIncident Oct 8, 2026
82f3cb3
Document explicit startup selection contract
MajorIncident Oct 8, 2026
8009a27
Cover failed Student resume recovery to startup
MajorIncident Oct 8, 2026
b9ed08e
Document startup hub capability separation
MajorIncident Oct 8, 2026
5a439cf
Freeze startup hub role-routing invariant
MajorIncident Oct 8, 2026
79705e1
Reconcile Classroom lifecycle with startup hub
MajorIncident Oct 8, 2026
8d0818c
Detect substantive Major Incident state semantically
MajorIncident Oct 9, 2026
3f3cfad
Cover real blank Major Incident defaults
MajorIncident Oct 9, 2026
91051b4
Diagnose mobile Notes activation and explicit reload resume
MajorIncident Oct 9, 2026
13a856b
Use touch activation for mobile Notes browser coverage
MajorIncident Oct 9, 2026
00035b3
Exercise Notes toggle button listener in mobile unit coverage
MajorIncident Oct 9, 2026
cc63201
Keep mobile Notes pointer activation targeted
MajorIncident Oct 9, 2026
9f94030
Verify click and touch activation for mobile Notes
MajorIncident Oct 9, 2026
289eb42
Cover Notes pointer capture safeguard
MajorIncident Oct 9, 2026
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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ The Standalone / Student / Instructor program is tracked by #288. Any work touch
Classroom invariants:

- experience role (`standalone | student | instructor`) is independent from intake mode and template kind;
- startup intent is explicit: `kt-experience-role-v1` is last-choice metadata only; substantive saved Intake, Student resume, and Instructor resume remain separate Continue contexts, and only explicit `?workspace=` Standalone authority bypasses the startup hub;
- experience/class/session state never enters `kt-intake-full-v2`, exported Intake files, summaries, or curated Intake payloads;
- Standalone remains backend-optional;
- Student/team editing reuses the existing collaboration snapshot/revision/presence engine;
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ KT Intake is a browser-first Kepner–Tregoe (KT) incident workbook designed for
## Quickstart
- Clone or download this repository.
- Open `index.html` in any modern browser. Standalone use remains local-first and does not depend on the classroom backend.
- A browser with no current experience preference asks whether to **Work independently**, **Join a class**, or **Teach a class**. Existing explicit `?workspace=` collaboration links still route to **Standalone**; saved Intake data by itself no longer silently chooses an experience.
- The selected experience resumes from the separate `kt-experience-role-v1` preference. Intake work itself still loads from `kt-intake-full-v2`, with action plans under `kt-actions-by-analysis-v1`.
- Ordinary launch opens the startup hub. Valid saved Intake, Student class, and Instructor class contexts appear as separate **Continue** cards; otherwise choose **Work independently**, **Join a class**, or **Run a class**. A safe `#join=` link highlights normal Student admission, while an explicit `?workspace=` collaboration link still routes directly to **Standalone**.
- `kt-experience-role-v1` remains a local-only last-choice preference, but it no longer auto-routes startup. Intake work itself still loads from `kt-intake-full-v2`, with action plans under `kt-actions-by-analysis-v1`.
- Use the header controls to **Save to File** (exports a JSON snapshot) or **Load from File** (imports a previously saved snapshot) when you need to move an intake between browsers or machines.
- Open the shared resource drawer to work with curated material. **Standalone** receives public Standard Templates only. Connected **Students** receive Standard Templates plus Classroom-authorized Case Studies; connected **Instructors** receive authorized teaching Case Studies. The rotating Case Study mode password remains a learning/progression control, not authentication.

Expand Down Expand Up @@ -72,7 +72,7 @@ See [`docs/architecture-overview.md`](docs/architecture-overview.md) for the boo
### Storage keys

- `kt-intake-full-v2`: Primary snapshot containing the intake form, table, steps, communications log, possible causes, and `notesWorkspace` notes/open preference. Save to File and Load from File include this full snapshot automatically.
- `kt-experience-role-v1`: Local-only Standalone / Student / Instructor preference. It is deliberately excluded from `collectAppState()`, Intake file exports, summaries, templates, and **Start Fresh** clearing.
- `kt-experience-role-v1`: Local-only Standalone / Student / Instructor last-choice preference. It is deliberately excluded from `collectAppState()`, Intake file exports, summaries, templates, and **Start Fresh** clearing, and does **not** silently choose startup routing.
- `kt-classroom-student-session-v1`: Student same-device resume key. Its current v2 envelope contains the stable Student class-session capability plus public class/participant/current-assignment context; the assignment-specific workspace capability remains memory-only and is reacquired after reload or reassignment. Older envelope formats are intentionally unsupported before production. The envelope never enters Intake exports/summaries/templates.
- `kt-classroom-student-local-recovery-v1`: Local recovery snapshot captured immediately before joining a class so **Leave class** can restore the prior local Intake. It is separate from the active Intake snapshot and classroom credentials.
- `kt-classroom-instructor-session-v1`: Local-only Instructor same-device resume envelope containing the Instructor class capability, public class metadata, and the last selected public workspace ID. It is never collected into Intake state, files, summaries, templates, or Student workspace credentials.
Expand All @@ -84,11 +84,13 @@ Coaching feedback is server-side Classroom data, not a local Intake storage key.

Experience role is a product-level choice, not an Intake workflow mode. General / IT / Pharma / Major Incident remain controlled by `meta.intakeMode`; Standalone / Student / Instructor are controlled separately by `src/experienceRoles.js` and `src/experienceRoleController.js`.

`src/startupExperienceHub.js` detects substantive saved Intake and current Student/Instructor resume envelopes independently. Opening the hub is non-destructive; starting a fresh independent Intake or replacing a same-type class resume requires explicit user intent.

**Administration / Maintenance is not an experience role.** It is a separate privileged utility entered from the chooser or View menu and authorized only by the server-configured `INTAKE_ADMIN_TOKEN`. See [`docs/admin-maintenance.md`](docs/admin-maintenance.md).

- **Standalone** exposes the normal Intake and current collaboration behavior. Its resource drawer contains **Templates only**.
- **Student** joins with a display name and one human class code. An Instructor share/QR link may prefill that same code through a client-only `#join=` fragment; the fragment is consumed locally and never replaces normal server admission. Admission creates a stable high-entropy Student class-session capability; the learner may remain **Waiting / unassigned** with no workspace edit authority until the Instructor assigns a team or individual workspace. Once assigned, the browser exchanges the class session for a fresh assignment-specific editable workspace capability, keeps that workspace capability memory-only, and attaches it to the existing collaboration engine without entering the URL. Reassignment disconnects old authority before the Student enters the destination team's existing Intake; unassign returns the Student to Waiting. Connected Students see class/workspace/identity context, public **Templates**, protected Classroom Case Studies, and read-only Instructor coaching including optional notes and **Changed since review**. On narrow screens the Class, Case, Team, and Notes secondary surfaces default compact but remain one-action accessible; those collapse states are presentation-only. Switching away pauses live classroom sync while preserving class resume; **Leave class** clears resume and restores the local Intake captured before joining.
- **Instructor** uses **Start a class**, receives one human Student join code, and can copy the code, share a fragment-only join link, or show a fully local QR for that same safe link. The Instructor sees Waiting/assigned participants, creates team or individual workspaces, and assigns/reassigns/unassigns Students through accessible selectors. The Instructor capability is retained locally for same-device resume; lost cross-device authority will be handled by the separately authorized Administration / Maintenance experience in #329 rather than a public bearer-code form. The dashboard can rapidly switch into a **live read-only** view of each Student/team Intake and provide field-level coaching. Observation uses the normal Intake renderer but server authorization keeps the Instructor credential outside Student edit capability. The same Instructor class capability authorizes protected teaching Case Studies. The Class rail defaults compact on narrow screens without changing session authority. Switching away pauses observation while preserving same-device class resume; **Leave class** clears the Instructor resume and restores the instructor's prior local Intake.
- **Instructor** uses **Start a class**, receives one human Student join code, and can copy the code, share a fragment-only join link, or show a fully local QR for that same safe link. The Instructor sees Waiting/assigned participants, creates team or individual workspaces, and assigns/reassigns/unassigns Students through accessible selectors. The Instructor capability is retained locally for same-device resume; lost cross-device authority is handled by the separately authorized Administration / Maintenance surface rather than a public bearer-code form. The dashboard can rapidly switch into a **live read-only** view of each Student/team Intake and provide field-level coaching. Observation uses the normal Intake renderer but server authorization keeps the Instructor credential outside Student edit capability. The same Instructor class capability authorizes protected teaching Case Studies. The Class rail defaults compact on narrow screens without changing session authority. Switching away pauses observation while preserving same-device class resume; **Leave class** clears the Instructor resume and restores the instructor's prior local Intake.
- Use **View → Experience** to switch roles without changing or deleting Intake data.

## Notes workspace
Expand Down
3 changes: 3 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ Administration / Maintenance is a separate privileged boundary documented in `do

Same-device Student resume stores the high-entropy **Student class-session capability** under `kt-classroom-student-session-v1` together with public class/participant/current-assignment context. The human join code is discarded after admission. The current assignment-specific workspace capability is **memory-only** and must be reacquired after reload or reassignment; it must not be written into the live resume envelope or URL. #328 intentionally rejects older pre-production Student session-envelope formats. No Student resume envelope may enter Intake state, exports, summaries, templates, analytics, logs, or error telemetry.

Startup presentation does not change these capability rules. `src/startupExperienceHub.js` may read current local resume envelopes only to decide whether to show a Continue card and to display non-secret context such as class title, participant display name, or workspace label. It must never render, copy, log, place in a URL, or otherwise disclose Student/Instructor bearer values. `kt-experience-role-v1` is last-choice metadata only and is never authorization or automatic startup authority. A safe `#join=<human-code>` fragment may highlight normal Student admission but remains admission-only and cannot substitute for Student session/workspace authority.


For same-device Instructor resume, the browser retains the Instructor class capability under `kt-classroom-instructor-session-v1` together with public class metadata, the human Student join code, and the last selected public workspace ID. This credential may administer/list/observe only its represented class through Instructor classroom APIs. It must never enter Intake state, exports, summaries, templates, URLs, analytics, logs, error telemetry, or `collaboration_workspace_capabilities`.

The human Student join code and Student class-session capability must never enumerate class workspaces or edit collaboration. Student own-status returns only the represented participant's assignment. Reassignment/unassign must revoke old workspace authority before destination/current access is issued, and stale old-team tokens must fail rather than map to the new team. Cross-class assignments fail without revealing unrelated class state. Instructor roster/workspace listing is scoped to the represented class.
Expand Down
5 changes: 3 additions & 2 deletions docs/AI-ONBOARDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ For any work in the Standalone / Student / Instructor program (#288), also read
## Entry Point & Boot Sequence
1. `index.html` renders the full layout and loads the ES module entry via `<script type="module" src="main.js"></script>`.
2. `main.js` registers a `DOMContentLoaded` listener that calls `boot()`.
3. `boot()` restores the independent product experience through `initExperienceRoleController()` before configuring the Intake feature modules. Existing saved Intakes / collaboration links become Standalone; genuinely new browsers receive the required chooser.
3. `boot()` initializes `src/startupExperienceHub.js` and `initExperienceRoleController()`. Ordinary launch stays unselected and shows explicit Continue/new-session choices; only an explicit `?workspace=` collaboration capability routes directly to Standalone.
4. `boot()` then performs the Intake initialization:
- Wires the KT helpers by calling `configureKT({ autoResize, updatePrefaceTitles, showToast, getObjectFull, getDeviationFull })`.
- Initialises each feature module: `initPreface`, `initializeCommunications`, `initStepsFeature`, `initTable`, `ensurePossibleCausesUI`, and `renderCauses`.
Expand All @@ -20,8 +20,9 @@ For any work in the Standalone / Student / Instructor program (#288), also read
| ------ | ----------- |
| `src/appState.js` | `collectAppState()`, `applyAppState()`, `getSummaryState()` for round-trip UI testing and summary hydration. |
| `src/experienceRoles.js` | Canonical Standalone / Student / Instructor IDs, labels, and declarative product-surface policy. |
| `src/experienceRoleController.js` | First-run chooser, current-format role resume/switching, join-link routing, and local-only `kt-experience-role-v1` preference. Pre-production raw-role and implicit saved-Intake migration compatibility is intentionally removed. |
| `src/experienceRoleController.js` | Applies Standalone/Student/Instructor surface projection, owns the startup/View dialog focus lifecycle, and persists the local-only `kt-experience-role-v1` last-choice preference. The preference is not startup authority. |
| `src/classroomStudent.js` | One-code Student admission, Waiting/own-status polling, current class-session resume, assignment-specific memory-only workspace access/reassignment/unassign, and coaching/resource lifecycle hooks. |
| `src/startupExperienceHub.js` | Detects substantive saved Intake and current Student/Instructor resumes independently, renders Continue cards, highlights safe `#join` intent, and owns explicit replacement confirmations. Delegates real class resume/revalidation to the Classroom controllers. |
| `src/adminMaintenance.js` | Administration / Maintenance dialog, tab-scoped Admin credential envelope, lifecycle inventory/filtering, recovery display, and signed preview/commit UX. It never sets an Intake experience role. |
| `src/classroomInstructor.js` | Start Class, human join-code display, same-device Instructor resume, live roster/team assignment management, read-only observation, and coaching lifecycle hooks. |
| `src/coachableFields.js` | Stable coaching target IDs and versioned field fingerprints; DOM placement is deliberately separate from persistence identity. |
Expand Down
5 changes: 3 additions & 2 deletions docs/architecture-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This document explains how the intake app boots, which modules own which DOM reg
`main.js` is the entry point referenced by `index.html`. Once `DOMContentLoaded` fires it runs `boot()`, which performs the following steps:

1. **Expose shared utilities** – assigns `window.showToast` first so modules and tests can emit notifications even before the rest of the UI finishes initializing.
2. **Restore the product experience role** – `initExperienceRoleController()` reads the separate `kt-experience-role-v1` preference. An explicit `?workspace=` link routes to Standalone, a valid saved preference resumes its role, and otherwise the chooser opens. Saved Intake data by itself does not choose a role. The controller applies only broad `data-experience-surface` visibility and never mutates Intake state.
2. **Resolve startup intent** – `src/startupExperienceHub.js` inspects substantive saved Intake plus current Student/Instructor resume envelopes and renders them as independent Continue choices. `initExperienceRoleController()` no longer auto-routes from `kt-experience-role-v1`; only an explicit `?workspace=` link bypasses the hub to Standalone. A safe `#join=` fragment biases Join without bypassing normal admission.
3. **Configure the KT table module** – calls `configureKT()` with callbacks owned by other modules:
- `autoResize` keeps textarea heights in sync with content.
- `onSave` points to `saveAppState()` so KT edits trigger persistence.
Expand Down Expand Up @@ -36,6 +36,7 @@ This document explains how the intake app boots, which modules own which DOM reg
| --- | --- | --- |
| `main.js` | Orchestrates boot, registers DOM listeners, wires file transfer + global shortcuts, exposes fallbacks for legacy integrations. | Relies on every feature module’s public API, but only coordinates them—it never reaches into DOM anchors it does not own. |
| `src/experienceRoles.js` & `src/experienceRoleController.js` | Define Standalone/Student/Instructor independently from Intake modes, persist the local-only role preference, own the role chooser, and project broad product surfaces. | Own `kt-experience-role-v1`, `[feature:experience-role]`, `[feature:experience-role-switch]`, Student notice, and Instructor shell. Experience state never enters `appState`. |
| `src/startupExperienceHub.js` | Detects meaningful saved Intake plus valid Student/Instructor resumes, renders explicit Continue cards, highlights safe join-link intent, and owns replacement confirmations. | Startup intent is navigation/session state only. It never writes resume choice into SerializedAppState and delegates actual class resume to the existing Classroom controllers. |
| `src/adminMaintenance.js` | Owns the privileged Administration / Maintenance overlay, tab-scoped Admin session envelope, lifecycle filters, Instructor recovery display, and preview-first destructive UX. | Calls only `/api/admin`; it never sets `data-experience-role` and never enters Intake persistence.
| `src/preface.js` | Manages `[section:preface]` + `[section:impact]` inputs, detection chips, mirror sync, and tokens such as `{OBJECT}` and `{DEVIATION}`. | Supplies `autoResize`, `updatePrefaceTitles`, `startMirrorSync`, `setBridgeOpenedNow`, `getPrefaceState`, `getObjectFull`, `getDeviationFull`. Receives `onSave` from `main.js`. |
| `src/kt.js` | Owns `[section:table]`: builds the IS/IS NOT table, possible-cause cards, focus modes, and cause evidence previews. | Accepts callbacks from Preface & Toast via `configureKT()`. Provides `exportKTTableState`, `importKTTableState`, `getPossibleCauses`, and other helpers consumed by `appState` & summary modules. |
Expand Down Expand Up @@ -71,7 +72,7 @@ This document explains how the intake app boots, which modules own which DOM reg

## Persistence and summary data flow

1. **Experience preference** – `src/experienceRoleController.js` reads/writes `kt-experience-role-v1` independently. It is not an input to `collectAppState()`, summary generation, file transfer, or template export.
1. **Experience preference / startup intent** – `src/experienceRoleController.js` reads/writes `kt-experience-role-v1` independently, but the preference is no longer startup authority. `src/startupExperienceHub.js` derives current Continue choices from real saved/resumable context. Neither is an input to `collectAppState()`, summary generation, file transfer, or template export.
2. **Student classroom resume** – `src/classroomStudent.js` reads/writes `kt-classroom-student-session-v1` and the pre-class `kt-classroom-student-local-recovery-v1` separately. Neither key is part of SerializedAppState; join/assignment capabilities are never persisted.
3. **Instructor classroom resume** – `src/classroomInstructor.js` reads/writes `kt-classroom-instructor-session-v1` separately. The Instructor class capability, public class metadata, and last selected public workspace ID never enter SerializedAppState, exports, summaries, or templates.
4. **Coaching feedback** – `src/classroomCoaching.js` has no Intake persistence key. Feedback lives server-side in `classroom_coaching_feedback`, with independent per-target revisions and reviewed field fingerprints; it never enters SerializedAppState, Save/Load, templates, summaries, or Student workspace revisions.
Expand Down
Loading
Loading