# GE-Enforce: the gea-shopfloor-display scope Displays are the share-less corner of the fleet. They are Intune/Entra-joined, credential-less kiosk PCs that pull their manifest over HTTPS on port 443 and authenticate with a read-only service PAT scoped `geenforce.fetch`, sent as `X-API-Key`. They have no SMB share mount. The kiosk engine and the kiosk browser are baked into the display image, not shipped over HTTPS, so the display manifest heals POLICY / CONFIG drift and inherited common entries, never EXEs. There are three display subtypes, selected by `C:\Enrollment\display-type.txt`: `Dashboard`, `Lobby`, and `3DPrintRoom`. ## Authoring the scope The scope is authored programmatically by `plugins/geenforce/seed_display_scope.py`, which builds a manifest dict and hands it to `service.replace_scope_draft` (the same call the `import-share` CLI uses), then attaches the inline dispatcher payload. From a Flask app context: ```python from plugins.geenforce.seed_display_scope import seed_display_scope seed_display_scope(publish=True) # publish=False leaves it as a draft ``` `replace_scope_draft` is an idempotent draft rebuild. `publish=True` additionally freezes an immutable published snapshot (that step is not idempotent: it always creates a new version). ### What the scope contains 1. Four `Registry` drift-heal entries that re-assert the Microsoft Edge kiosk relaunch policies set at imaging by `09-Setup-Display.ps1`. Each writes the value and detects drift with `DetectionMethod = ValueMatches` against the same path/name, so a display that loses a policy self-heals on the next enforce cycle with no keyboard or mouse on site: - `RelaunchNotification = 2` (DWord, Required auto-restart) - `RelaunchNotificationPeriod = 3600000` (DWord, 1 hour) - `RelaunchHeadsUpPeriod = 60000` (DWord, 1 minute) - `RelaunchWindow` (String, JSON, 02:00 start, 120 minute duration) 2. One `PS1` dispatcher, delivered inline over HTTPS. It reads `C:\Enrollment\display-type.txt` and launches the kiosk target for the subtype. The subtype -> route map is a data-driven table (`DISPLAY_TYPE_TARGETS`) at the top of both the seed module and the generated script, so targets are easy to edit. `DetectionMethod = Always` so it re-asserts each cycle, but the script is idempotent (it skips relaunch if a kiosk process is already serving the target URL). ### display-type -> target map | display-type.txt | kiosk route | notes | | --- | --- | --- | | `Dashboard` | `/shopfloor` | core ShopfloorDashboard, standalone full-screen | | `Lobby` | `/tv` | slides plugin TV dashboard (surface `lobby`) | | `3DPrintRoom` | `/parts-kiosk` | **PLACEHOLDER, TODO-confirm** printedparts parts kiosk route; confirm the real 3D-print-room target with the floor team before publishing to production displays | ## Inheritance: the client merges common The manifest model has no inheritance column. The display scope is a plain (non-common) runtime scope carrying only display-specific entries. The CLIENT merges the fleet-wide `common` scope underneath the display scope at fetch time. So `common` is where the fleet-wide policy/config/self-update entries live, and `gea-shopfloor-display` adds the kiosk-only entries on top. ## Blocker: common carries SMB payloads that break on share-less displays Before a share-less display can safely inherit `common`, every `common` entry that pulls a payload file from the SMB share must first be given an `http` or `inline` payload (with a `payloadsha256`). A display has no share mount, so any inherited entry whose `Installer` / `Source` / `Script` resolves to a share-relative path will fail its fetch. Registry entries in `common` carry no payload (they write inline reg values) and are safe to inherit as-is. The entries below reference a share file and must be converted first. This audit is the authoritative to-convert list; the payload bytes themselves are not converted here (that needs the real payload files). Common entries that reference an SMB/share payload (as of the on-share `common/manifest.json`, 22 entries, Version 2.0): | # | Common entry | Type | Share payload | Field | | --- | --- | --- | --- | --- | | 1 | Adobe Acrobat Reader DC | CMD | `scripts/Install-AcroReader.cmd` | Installer | | 2 | Migrate pc-type.txt to gea-shopfloor-* taxonomy | PS1 | `scripts/Migrate-PCType.ps1` | Script | | 3 | WJF Defect Tracker | MSI | `apps/WJF_Defect_Tracker.msi` | Installer | | 4 | 3OF9 barcode font | File | `configs/3OF9.ttf` | Source | | 5 | Edge IE-Mode site list | File | `configs/enterprise-mode-site-list.xml` | Source | | 6 | Ensure VNC firewall rule | PS1 | `scripts/ensure-vnc-firewall.ps1` | Script | | 7 | FMS hosts pin (WJFMS3.AE.GE.COM) | PS1 | `scripts/Set-FmsHostsEntry.ps1` | Script | | 8 | Oracle Client 11.2 | CMD | `scripts/Install-Oracle11r2.cmd` | Installer | | 9 | PrinterInstallerMap (site-map printer installer) | File | `apps/PrinterInstallerMap.exe` | Source | | 10 | OpenText HostExplorer ShopFloor | CMD | `scripts/Setup-OpenText.cmd` | Installer | | 11 | GE-Enforce dispatcher (self-update) | File | `GE-Enforce.ps1` | Source | | 12 | Install-FromManifest lib (self-update) | File | `lib/Install-FromManifest.ps1` | Source | | 13 | Report asset (host + IP + machine number) to ShopDB | PS1 | `apps/Report-AssetToShopDB.ps1` | Script | | 14 | EventSaver screensaver (binary) | File | `apps/EventSaver.scr` | Source | | 15 | EventSaver screensaver (config) | File | `configs/EventSaver.ini` | Source | | 16 | EventSaver enable (per-user screensaver) | PS1 | `scripts/Set-EventSaverScreensaver.ps1` | Script | | 17 | EventSaver power (keep monitor awake) | PS1 | `scripts/Set-EventSaverPower.ps1` | Script | | 18 | EventSaver disable (measuring-tool bays) | PS1 | `scripts/Set-EventSaverDisable.ps1` | Script | | 19 | EventSaver disable (specific hostnames) | PS1 | `scripts/Set-EventSaverDisable.ps1` | Script | Safe to inherit as-is (Registry entries, no share payload): `3OF9 barcode font registry entry`, `Edge IE-Mode policy level`, `Edge IE-Mode policy site list pointer`. Not every entry above is relevant to a display (a display needs no Oracle client, OpenText, or Defect Tracker), so a follow-up decision is which common entries a display should actually run (via `PCTypes` targeting) versus which must be repackaged as `http`/`inline`. But any that survive targeting must have a non-SMB payload before displays inherit common.