From 5f2c3e9612d6e910e59d2fdbadbcb10860552e75 Mon Sep 17 00:00:00 2001
From: alixthegreat <146326639+alixxhiscock@users.noreply.github.com>
Date: Sat, 11 Apr 2026 16:52:48 +0100
Subject: [PATCH 1/4] Add implementation plan for sis configuration threshold
---
...iguration_threshold_implementation_plan.md | 247 ++++++++++++++++++
1 file changed, 247 insertions(+)
create mode 100644 planning_notes/sis-configuration-threshold/sis_configuration_threshold_implementation_plan.md
diff --git a/planning_notes/sis-configuration-threshold/sis_configuration_threshold_implementation_plan.md b/planning_notes/sis-configuration-threshold/sis_configuration_threshold_implementation_plan.md
new file mode 100644
index 00000000..3254e989
--- /dev/null
+++ b/planning_notes/sis-configuration-threshold/sis_configuration_threshold_implementation_plan.md
@@ -0,0 +1,247 @@
+# SIS Configuration Threshold Display (Scenario 2) Implementation Plan
+
+Date: 2026-04-11
+Owner: Break Escape engineering
+Scope: Implement the Scenario 2 SIS configuration threshold minigame with minimal code changes and full narrative/state integration.
+
+## 1. Source Alignment and Scope
+
+This plan is aligned to:
+
+- planning_notes/sis_scenarios/case_2_energy_game_design/minigame_planning.md
+- planning_notes/sis_scenarios/case_2_energy_game_design/development_tasks.csv
+- planning_notes/sis_scenarios/case_2_energy_game_design/case_2_energy_gdd.md
+- planning_notes/sis_scenarios/case_2_energy_game_design/new_objects_planning.md
+- planning_notes/sis_scenarios/case_2_energy_information_pack/requirements/claims.md
+- scenarios/sis02_energy/scenario.json.erb
+- scenarios/sis02_energy/mission.json
+- scenarios/sis02_energy/ink/INK_DEVELOPMENT_SUMMARY.md
+
+Note on path request:
+
+- scenarios/sis02_healthcare does not exist in this repo.
+- Scenario 2 implementation target is scenarios/sis02_energy.
+
+## 2. Canonical Feature Definition
+
+Feature name: SIS Configuration Threshold Display
+
+Intended behavior:
+
+- Interactive minigame opened from the Engineering Workshop SIS panel object.
+- Shows a setpoint table: parameter, current value, certified baseline, deviation status, last-modified, modified-by.
+- Deviation rows are highlighted and expandable for explanatory detail.
+- Compare workflow is delivered in a stub-compatible way in phase 1 (no new globals), with stricter certification gating deferred to phase 2 if needed.
+- Confirm action records tamper confirmation and advances narrative logic.
+
+Core teaching moment:
+
+- THERMAL_RUNAWAY_THRESHOLD changed from 55C certified baseline to 85C current value.
+
+## 3. Known Naming Drift (Must Resolve Before Coding)
+
+There is MG ID drift across docs:
+
+- minigame_planning labels SIS display as MG-03.
+- development_tasks labels SIS display as MG-02.
+
+Implementation rule:
+
+- Use feature/object identity, not MG number:
+ - object id: sis_config_panel
+ - behavior: SIS Configuration Threshold Display
+
+There is variable naming drift across docs:
+
+- sis_certification_seen
+- sis_cert_reviewed
+- current scenario uses sis_config_seen and sets sis_tamper_confirmed from document read.
+
+Scenario 2 stub precedence rule (source of truth for implementation phase 1):
+
+- Keep existing globals and placeholder flow already defined in scenarios/sis02_energy/scenario.json.erb.
+- Do not introduce new global variable names in phase 1.
+- Use current globals as implemented in scenario stub:
+ - sis_config_seen
+ - sis_tamper_confirmed
+ - en002_claim_assessed
+
+Variable governance rule (authoritative for implementation):
+
+- planning_notes/sis_scenarios/case_2_energy_game_design defines intended gameplay concepts.
+- scenarios/sis02_energy/scenario.json.erb defines authoritative current variable names for implementation.
+- If a new global variable becomes necessary, request user approval before adding it.
+
+Optional phase 2 cleanup:
+
+- Add a dedicated certification-reviewed global only if needed after phase 1 is stable.
+
+## 4. Dependency Map
+
+Scenario objects:
+
+- sis_config_panel (engineering workshop): launch point for minigame
+- SIS certification document object (filing cabinet): enables compare workflow
+
+Global variables read:
+
+- sis_config_seen (existing open/read marker)
+- sis_tamper_confirmed (existing progression marker; also for reopen idempotency)
+
+Global variables written:
+
+- sis_config_seen
+- sis_tamper_confirmed
+- en002_claim_assessed
+
+Narrative and progression dependencies:
+
+- Priya branch unlocks on sis_tamper_confirmed
+- Dr Bashir debrief logic references sis_tamper_confirmed
+- Alarm panel state logic references sis_tamper_confirmed (current or future engine behavior)
+- Objectives/tasks tied to SIS investigation complete through existing event mappings and globals
+
+Claims linkage:
+
+- EN-002 is the primary claim teaching link for this minigame.
+
+## 5. Minimal Technical Implementation Plan
+
+### 5.1 Files to Add
+
+1. public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js
+
+- New minigame class extending MinigameScene.
+- Render table UI in DOM/CSS (consistent with existing HTML/CSS minigame patterns).
+- Read scenario params for table rows and labels.
+- Emit state updates through existing global variable update pathway.
+
+2. public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold.css (optional)
+
+- Keep inline styles only if consistent with local minigame style patterns.
+- Prefer scoped CSS class names if using style injection in JS.
+
+### 5.2 Files to Update
+
+1. public/break_escape/js/minigames/index.js
+
+- Import/export/register scene name: sis-config-threshold.
+
+2. public/break_escape/js/systems/interactions.js
+
+- Add object type handler for sis_config_panel (or explicit id fallback).
+- Start minigame via MinigameFramework.startMinigame with scenarioData payload.
+
+3. scenarios/sis02_energy/scenario.json.erb
+
+- Convert current readable placeholder for sis_config_panel into minigame-backed object config.
+- Preserve existing stub globals and placeholder naming.
+- Build minigame behavior from existing sis_config_panel stub content (same setpoints, same narrative text intent).
+- Keep certification-document interaction compatible with current scenario flow in phase 1.
+- Only adjust global writes when required to avoid bypassing the minigame, and keep objective/NPC behavior unchanged.
+
+### 5.3 Data Contract (scenarioData)
+
+Suggested shape:
+
+- type: sis_config_panel
+- title: SIS CONFIGURATION - BATTERY HALL SIS
+- rows: []
+ - parameter
+ - currentValue
+ - certifiedValue
+ - status (GREEN/AMBER/RED)
+ - lastModified
+ - modifiedBy
+ - detailText
+- compare:
+ - requiresGlobal: sis_tamper_confirmed (phase 1 fallback to existing globals only)
+ - disabledHint
+- actions:
+ - confirmSets:
+ - sis_tamper_confirmed: true
+ - en002_claim_assessed: true
+ - openSets:
+ - sis_config_seen: true
+
+## 6. UI/Visual Design Specification
+
+Style direction:
+
+- Industrial SIS panel UI, small-control-system feel, no rounded corners.
+- Use strong table hierarchy and high-contrast status highlights.
+
+Visual requirements:
+
+- Header: SIS configuration title bar.
+- Main: tabular setpoint grid with clear certified vs current columns.
+- Deviation rows: amber/red emphasis with warning glyph.
+- Expanded explanation panel/modal for clicked deviation row.
+- Compare button:
+ - phase 1: use existing stub-compatible behavior (no new certification-reviewed global)
+ - phase 2 (optional): add strict certification-reviewed gating
+- Confirm button:
+ - explicit irreversible confirmation dialog
+ - completion state shown before close
+
+Animation/motion (minimal):
+
+- subtle row highlight pulse for deviated row
+- panel slide/fade for compare overlay
+- no excessive animation
+
+Accessibility/readability:
+
+- ensure legible type size for desktop and wall-monitor use
+- color is not the sole signal; include status text labels
+
+## 7. Integration Behavior (End-to-End)
+
+1. Player opens sis_config_panel.
+2. Minigame opens and sets sis_config_seen=true.
+3. Player inspects rows and can expand deviation details.
+4. Compare feature follows phase 1 stub-compatible behavior (strict cert-review gating deferred unless a dedicated global is introduced later).
+5. Player confirms tamper.
+6. System sets sis_tamper_confirmed=true and en002_claim_assessed=true.
+7. Existing event mappings/dialogue/objective logic progress without additional custom engine work.
+
+Implementation note for phase 1:
+
+- Since no dedicated certification-reviewed global currently exists in scenario stub, comparison gating must be implemented without adding new globals (or deferred while keeping the rest of the minigame fully functional).
+
+## 8. Acceptance Criteria
+
+Functional:
+
+- Minigame launches from sis_config_panel interaction.
+- Correct setpoint values are displayed, including 55C vs 85C thermal threshold mismatch.
+- Compare workflow behaves consistently with phase 1 stub constraints and does not require new globals.
+- Confirm action updates required globals once, idempotently.
+- Existing scenario placeholder globals remain the authority for progression.
+
+Narrative/system:
+
+- Priya and Dr Bashir SIS branches unlock as expected after confirm.
+- No regression to objective progression.
+- Alarm panel/SIS status references remain coherent with sis_tamper_confirmed.
+
+Quality/minimality:
+
+- No new engine subsystem introduced.
+- Changes limited to minigame registration, interaction routing, and scenario object/global wiring.
+
+## 9. Implementation Order
+
+1. Build minigame scene directly from current sis_config_panel placeholder values/content.
+2. Register and wire interaction handler.
+3. Update scenario object to launch minigame while preserving existing Scenario 2 globals.
+4. Remove or narrow only the minimum placeholder bypass logic necessary.
+5. Run targeted Scenario 2 SIS progression test (objectives + Priya/Dr Bashir branches).
+
+## 10. Out of Scope for This Implementation
+
+- New timer engines, alarm panel driver engines, or hardware GPIO behavior.
+- Reworking unrelated MG IDs across all planning docs.
+- Large UI framework introduction.
+
+This keeps implementation minimal while fully delivering the SIS threshold discovery teaching objective for Scenario 2.
From 980bc2c091e049ed6cae255e640c8dba265d2178 Mon Sep 17 00:00:00 2001
From: alixthegreat <146326639+alixxhiscock@users.noreply.github.com>
Date: Sat, 11 Apr 2026 18:10:48 +0100
Subject: [PATCH 2/4] Add sis configuration threshold minigame
---
app/views/break_escape/games/show.html.erb | 1 +
index.html | 1 +
.../css/sis-config-threshold-minigame.css | 265 ++++++++++++++++
public/break_escape/js/minigames/index.js | 4 +
.../sis-config-threshold-minigame.js | 288 ++++++++++++++++++
.../break_escape/js/systems/interactions.js | 14 +
scenarios/sis02_energy/scenario.json.erb | 43 ++-
7 files changed, 611 insertions(+), 5 deletions(-)
create mode 100644 public/break_escape/css/sis-config-threshold-minigame.css
create mode 100644 public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js
diff --git a/app/views/break_escape/games/show.html.erb b/app/views/break_escape/games/show.html.erb
index 3ecbf67a..38c683a6 100644
--- a/app/views/break_escape/games/show.html.erb
+++ b/app/views/break_escape/games/show.html.erb
@@ -43,6 +43,7 @@
+
diff --git a/index.html b/index.html
index a2452022..29982fea 100644
--- a/index.html
+++ b/index.html
@@ -51,6 +51,7 @@
+
diff --git a/public/break_escape/css/sis-config-threshold-minigame.css b/public/break_escape/css/sis-config-threshold-minigame.css
new file mode 100644
index 00000000..83faba21
--- /dev/null
+++ b/public/break_escape/css/sis-config-threshold-minigame.css
@@ -0,0 +1,265 @@
+/* SIS Config Threshold Minigame Styles */
+
+.sis-threshold-minigame-container {
+ background: rgba(13, 20, 32, 0.72);
+ border: 2px solid #2b3446;
+}
+
+.sis-threshold-minigame-game-container {
+ max-width: 620px;
+ margin: 20px auto;
+ width: 100%;
+ background: rgba(17, 26, 40, 0.78) !important;
+ border: 2px solid #263246;
+ box-shadow: inset 0 0 18px rgba(0, 0, 0, 0.5);
+ padding: 12px;
+ height: 50vh;
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+}
+
+.sis-threshold {
+ font-family: 'VT323', 'Courier New', monospace;
+ color: #e9edf5;
+ padding: 8px;
+ width: 100%;
+ min-height: 100%;
+ position: relative;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.sis-threshold-header {
+ background: #133f73;
+ border: 2px solid #2b5d93;
+ padding: 10px 12px;
+ font-size: 18px;
+ letter-spacing: 0.4px;
+}
+
+.sis-threshold-table {
+ width: 100%;
+ border-collapse: collapse;
+ margin-top: 10px;
+ font-size: 16px;
+}
+
+.sis-threshold-table th,
+.sis-threshold-table td {
+ border: 2px solid #2a2f3b;
+ padding: 8px;
+ text-align: left;
+ vertical-align: top;
+}
+
+.sis-threshold-table th {
+ background: #1f2b3f;
+ color: #e9edf5;
+}
+
+.sis-row {
+ background: #212733;
+ cursor: default;
+}
+
+.sis-row-clickable {
+ cursor: pointer;
+}
+
+.sis-row-clickable:hover {
+ background: #313744;
+}
+
+.sis-status-green {
+ color: #84d78a;
+ font-weight: 700;
+}
+
+.sis-status-amber {
+ color: #ffd14b;
+ font-weight: 700;
+}
+
+.sis-status-red {
+ color: #ff6a6a;
+ font-weight: 700;
+}
+
+.sis-row-meta {
+ color: #9ea7b7;
+ font-size: 14px;
+ margin-top: 4px;
+}
+
+.sis-actions {
+ display: flex;
+ gap: 10px;
+ margin-top: 14px;
+ flex-wrap: wrap;
+}
+
+.sis-btn {
+ border: 4px solid #2980b9;
+ border-radius: 0;
+ padding: 10px 20px;
+ font-family: 'VT323', monospace;
+ font-size: 18px;
+ cursor: pointer;
+ background: #3498db;
+ color: #fff;
+ transition: background 0.3s, box-shadow 0.2s ease, transform 0.15s ease, filter 0.2s ease;
+}
+
+.sis-btn-compare {
+ background: #b88d21;
+ color: #fff;
+ border-color: #8d6f1c;
+}
+
+.sis-btn-compare[disabled] {
+ background: #5d5d5d;
+ color: #cfcfcf;
+ cursor: not-allowed;
+}
+
+.sis-btn-confirm {
+ background: #b32424;
+ color: #fff;
+ border-color: #7e1a1a;
+}
+
+.sis-btn-compare:hover {
+ box-shadow: 0 0 12px rgba(255, 209, 75, 0.45);
+ filter: brightness(1.08);
+ transform: translateY(-1px);
+}
+
+.sis-btn-confirm:hover {
+ background: #8f1f1f;
+ border-color: #6d1616;
+ box-shadow: none;
+ filter: none;
+ transform: none;
+}
+
+.sis-btn:active {
+ transform: translateY(0);
+ background: #21618c;
+}
+
+.sis-btn-confirm:active {
+ background: #731818;
+ border-color: #5d1212;
+}
+
+.sis-help {
+ margin-top: 8px;
+ color: #c9cfd9;
+ font-size: 14px;
+}
+
+.sis-overlay {
+ position: absolute;
+ inset: 0;
+ background: rgba(6, 10, 18, 0.32);
+ display: none;
+ align-items: center;
+ justify-content: center;
+ padding: 8px;
+ z-index: 5;
+ box-sizing: border-box;
+}
+
+.sis-overlay.show {
+ display: flex;
+}
+
+.sis-modal {
+ background: #161c26;
+ border: 2px solid #3c4d68;
+ max-width: 100%;
+ width: 100%;
+ padding: 14px;
+ box-sizing: border-box;
+ margin: 0 auto;
+}
+
+.sis-modal h4 {
+ margin: 0 0 8px 0;
+ color: #f4f7fb;
+ font-size: 20px;
+}
+
+.sis-modal p {
+ margin: 0;
+ color: #d3dae5;
+ font-size: 16px;
+ line-height: 1.35;
+}
+
+.sis-modal-actions {
+ margin-top: 12px;
+ display: flex;
+ gap: 8px;
+ justify-content: flex-end;
+}
+
+/* Match popup action buttons to framework minigame-button style exactly */
+.sis-modal-actions .sis-btn:not(.sis-btn-compare):not(.sis-btn-confirm) {
+ background: #3498db;
+ color: white;
+ border: 4px solid #2980b9;
+ padding: 10px 20px;
+ font-family: 'VT323', monospace;
+ font-size: 18px;
+}
+
+.sis-modal-actions .sis-btn:not(.sis-btn-compare):not(.sis-btn-confirm):hover {
+ background: #2980b9;
+ box-shadow: none;
+ filter: none;
+ transform: none;
+}
+
+.sis-modal-actions .sis-btn:not(.sis-btn-compare):not(.sis-btn-confirm):active {
+ background: #21618c;
+ transform: none;
+}
+
+.sis-compare-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 10px;
+ margin-top: 8px;
+ align-items: stretch;
+}
+
+.sis-compare-card {
+ border: 2px solid #2b3443;
+ background: #202735;
+ padding: 10px;
+ min-height: 132px;
+ box-sizing: border-box;
+}
+
+.sis-compare-card h5 {
+ margin: 0 0 6px 0;
+ font-size: 18px;
+ color: #f4f7fb;
+}
+
+.sis-compare-item {
+ margin: 0 0 6px 0;
+ font-size: 17px;
+ line-height: 1.35;
+ color: #eef3ff;
+ word-break: break-word;
+}
+
+.sis-compare-item-alert {
+ color: #ffd46b;
+ font-weight: 700;
+}
diff --git a/public/break_escape/js/minigames/index.js b/public/break_escape/js/minigames/index.js
index 505204c4..46a9b9d8 100644
--- a/public/break_escape/js/minigames/index.js
+++ b/public/break_escape/js/minigames/index.js
@@ -25,6 +25,7 @@ export { EhrTerminalMinigame } from './ehr-terminal/ehr-terminal-minigame.js';
export { BackupRecoveryMinigame } from './backup-recovery/backup-recovery-minigame.js';
export { CommandBoardMinigame } from './command-board/command-board-minigame.js';
export { InfusionPumpMinigame } from './infusion-pump/infusion-pump-minigame.js';
+export { SisConfigThresholdMinigame, startSisConfigThresholdMinigame } from './sis-config-threshold/sis-config-threshold-minigame.js';
// Initialize the global minigame framework for backward compatibility
import { MinigameFramework } from './framework/minigame-manager.js';
@@ -95,6 +96,7 @@ import { SiemDashboardMinigame } from './siem/siem-dashboard-minigame.js';
import { EhrTerminalMinigame } from './ehr-terminal/ehr-terminal-minigame.js';
import { CommandBoardMinigame } from './command-board/command-board-minigame.js';
import { InfusionPumpMinigame } from './infusion-pump/infusion-pump-minigame.js';
+import { SisConfigThresholdMinigame, startSisConfigThresholdMinigame } from './sis-config-threshold/sis-config-threshold-minigame.js';
// Import ransomware display minigame
import { RansomwareDisplayMinigame } from './ransomware-display/ransomware-display-minigame.js';
@@ -127,6 +129,7 @@ MinigameFramework.registerScene('ehr-terminal', EhrTerminalMinigame);
MinigameFramework.registerScene('backup-recovery', BackupRecoveryMinigame);
MinigameFramework.registerScene('command-board', CommandBoardMinigame);
MinigameFramework.registerScene('infusion-pump', InfusionPumpMinigame);
+MinigameFramework.registerScene('sis-config-threshold', SisConfigThresholdMinigame);
// Make minigame functions available globally
window.startNotesMinigame = startNotesMinigame;
@@ -143,3 +146,4 @@ window.startTitleScreenMinigame = startTitleScreenMinigame;
window.startRFIDMinigame = startRFIDMinigame;
window.returnToConversationAfterRFID = returnToConversationAfterRFID;
window.startNetworkSegmentationMapMinigame = startNetworkSegmentationMapMinigame;
+window.startSisConfigThresholdMinigame = startSisConfigThresholdMinigame;
diff --git a/public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js b/public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js
new file mode 100644
index 00000000..067f1113
--- /dev/null
+++ b/public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js
@@ -0,0 +1,288 @@
+import { MinigameScene } from '../framework/base-minigame.js';
+
+const DEFAULT_ROWS = [
+ {
+ parameter: 'THERMAL_RUNAWAY_THRESHOLD',
+ currentValue: '85C',
+ certifiedValue: '55C',
+ status: 'AMBER',
+ lastModified: '03:22 (today)',
+ modifiedBy: 'engineering_access',
+ detailText: 'This value deviates from the IEC 61511 certified baseline. Possible causes: (1) authorised maintenance change requiring recertification, (2) unauthorised modification.'
+ },
+ {
+ parameter: 'H2_ALARM_THRESHOLD',
+ currentValue: '1.2% LEL',
+ certifiedValue: '1.0% LEL',
+ status: 'AMBER',
+ lastModified: '03:22 (today)',
+ modifiedBy: 'engineering_access',
+ detailText: 'Hydrogen trip threshold has been raised above certified baseline, reducing early-warning margin.'
+ },
+ {
+ parameter: 'MAX_CHARGE_VOLTAGE',
+ currentValue: '4.32 V/cell',
+ certifiedValue: '4.25 V/cell',
+ status: 'AMBER',
+ lastModified: '03:22 (today)',
+ modifiedBy: 'engineering_access',
+ detailText: 'Overcharge protection limit exceeds certified value, increasing thermal risk during charging.'
+ }
+];
+
+const CERTIFICATION_DOC_NAME = 'SIS Certification Document (IEC 61511)';
+
+function normalizeStatus(status) {
+ return String(status || 'GREEN').toUpperCase();
+}
+
+export class SisConfigThresholdMinigame extends MinigameScene {
+ constructor(container, params = {}) {
+ super(container, params);
+ this.rows = Array.isArray(params.rows) && params.rows.length > 0 ? params.rows : DEFAULT_ROWS;
+ this.compareTitle = params.compareTitle || 'Certification Comparison';
+ this.confirmLabel = params.confirmLabel || 'Confirm SIS Tamper - Report to Security';
+ }
+
+ init() {
+ this.params.title = this.params.title || 'SIS Configuration - Battery Hall SIS';
+ this.params.cancelText = this.params.cancelText || 'Close';
+ super.init();
+
+ // Keep SIS panel footprint similar to PIN minigame and style as translucent panel.
+ this.container.className += ' sis-threshold-minigame-container';
+ this.gameContainer.className += ' sis-threshold-minigame-game-container';
+
+ this.setScenarioGlobal('sis_config_seen', true);
+ this.render();
+ this.bindEvents();
+ }
+
+ render() {
+ const container = document.createElement('div');
+ container.className = 'sis-threshold';
+
+ const canCompare = this.hasCertificationDoc();
+
+ const tableRows = this.rows.map((row, index) => {
+ const status = normalizeStatus(row.status);
+ const statusClass = status === 'RED' ? 'sis-status-red' : status === 'AMBER' ? 'sis-status-amber' : 'sis-status-green';
+ const clickableClass = status === 'GREEN' ? '' : 'sis-row-clickable';
+
+ return `
+
+ |
+ ${row.parameter || ''}
+ ${row.lastModified || ''} | ${row.modifiedBy || ''}
+ |
+ ${row.currentValue || ''} |
+ ${status} |
+
+ `;
+ }).join('');
+
+ container.innerHTML = `
+
+
+
+
+ | Parameter |
+ Current Value |
+ Status |
+
+
+
+ ${tableRows}
+
+
+
+
+
+
+
+ ${canCompare ? 'Select highlighted rows to inspect deviations.' : 'Retrieve the SIS certification document to unlock side-by-side comparison.'}
+
+
+ `;
+
+ this.gameContainer.appendChild(container);
+
+ this.overlayEl = container.querySelector('#sis-detail-overlay');
+ this.helpTextEl = container.querySelector('#sis-help-text');
+ }
+
+ bindEvents() {
+ this.gameContainer.querySelectorAll('tr[data-clickable="true"]').forEach((rowEl) => {
+ this.addEventListener(rowEl, 'click', () => {
+ const index = Number(rowEl.getAttribute('data-row-index'));
+ const row = this.rows[index];
+ this.showDetail(row);
+ });
+ });
+
+ const compareBtn = this.gameContainer.querySelector('#sis-compare-btn');
+ if (compareBtn) {
+ this.addEventListener(compareBtn, 'click', () => {
+ if (!this.hasCertificationDoc()) return;
+ this.showCompare();
+ });
+ }
+
+ const confirmBtn = this.gameContainer.querySelector('#sis-confirm-btn');
+ if (confirmBtn) {
+ this.addEventListener(confirmBtn, 'click', () => {
+ this.showConfirm();
+ });
+ }
+ }
+
+ hasCertificationDoc() {
+ const items = window.inventory?.items || [];
+ const hasInventoryDoc = items.some((item) => {
+ const name = item?.scenarioData?.name || item?.name || '';
+ return String(name).trim() === CERTIFICATION_DOC_NAME;
+ });
+
+ if (hasInventoryDoc) return true;
+
+ const notes = window.gameState?.notes || [];
+ return notes.some((note) => String(note?.title || '').trim() === CERTIFICATION_DOC_NAME);
+ }
+
+ showDetail(row) {
+ if (!this.overlayEl || !row) return;
+
+ const detailText = row.detailText || 'This value deviates from the IEC 61511 certified baseline.';
+ this.overlayEl.innerHTML = `
+
+
${row.parameter || 'Parameter Detail'}
+
${detailText}
+
+
+
+
+ `;
+ this.overlayEl.classList.add('show');
+
+ const closeBtn = this.overlayEl.querySelector('#sis-detail-close');
+ this.addEventListener(closeBtn, 'click', () => this.closeOverlay());
+ }
+
+ showCompare() {
+ if (!this.overlayEl) return;
+
+ const currentRows = this.rows.map((row) => {
+ const status = normalizeStatus(row.status);
+ const className = status === 'GREEN' ? 'sis-compare-item' : 'sis-compare-item sis-compare-item-alert';
+ return `${row.parameter}: ${row.currentValue}
`;
+ }).join('');
+
+ const certifiedRows = this.rows.map((row) => {
+ return `${row.parameter}: ${row.certifiedValue}
`;
+ }).join('');
+
+ this.overlayEl.innerHTML = `
+
+
${this.compareTitle}
+
+
+
Current SIS Values
+ ${currentRows}
+
+
+
Certified Reference (IEC 61511)
+ ${certifiedRows}
+
+
+
+
+
+
+ `;
+ this.overlayEl.classList.add('show');
+
+ const closeBtn = this.overlayEl.querySelector('#sis-compare-close');
+ this.addEventListener(closeBtn, 'click', () => this.closeOverlay());
+ }
+
+ showConfirm() {
+ if (!this.overlayEl) return;
+
+ this.overlayEl.innerHTML = `
+
+
Confirm SIS Tamper Report
+
Report detected SIS setpoint deviations to security operations?
+
+
+
+
+
+ `;
+ this.overlayEl.classList.add('show');
+
+ const noBtn = this.overlayEl.querySelector('#sis-confirm-no');
+ const yesBtn = this.overlayEl.querySelector('#sis-confirm-yes');
+ this.addEventListener(noBtn, 'click', () => this.closeOverlay());
+ this.addEventListener(yesBtn, 'click', () => this.applyConfirm());
+ }
+
+ applyConfirm() {
+ this.setScenarioGlobal('sis_tamper_confirmed', true);
+
+ this.gameResult = {
+ reported: true,
+ source: 'sis-config-threshold'
+ };
+
+ this.closeOverlay();
+ this.showSuccess('SIS tamper reported. Priya has been notified.', true, 900);
+ }
+
+ closeOverlay() {
+ if (!this.overlayEl) return;
+ this.overlayEl.classList.remove('show');
+ this.overlayEl.innerHTML = '';
+ }
+
+ setScenarioGlobal(name, value) {
+ if (window.npcManager?.setGlobalVariable) {
+ window.npcManager.setGlobalVariable(name, value);
+ return;
+ }
+
+ if (!window.gameState) window.gameState = {};
+ if (!window.gameState.globalVariables) window.gameState.globalVariables = {};
+
+ const oldValue = window.gameState.globalVariables[name];
+ window.gameState.globalVariables[name] = value;
+
+ if (window.eventDispatcher) {
+ window.eventDispatcher.emit(`global_variable_changed:${name}`, {
+ name,
+ value,
+ oldValue
+ });
+ }
+ }
+}
+
+export function startSisConfigThresholdMinigame(sprite = null) {
+ if (!window.MinigameFramework) {
+ console.error('[SIS] MinigameFramework not available');
+ return;
+ }
+
+ const scenarioData = sprite?.scenarioData || {};
+ const minigameData = scenarioData.minigame || {};
+
+ const params = {
+ title: minigameData.title || scenarioData.name || 'SIS Configuration Panel',
+ rows: Array.isArray(minigameData.rows) ? minigameData.rows : [],
+ compareTitle: minigameData.compareTitle || 'Compare with Certification Document',
+ confirmLabel: minigameData.confirmLabel || 'Confirm SIS Tamper - Report to Security'
+ };
+
+ window.MinigameFramework.startMinigame('sis-config-threshold', null, {
+ ...params
+ });
+}
diff --git a/public/break_escape/js/systems/interactions.js b/public/break_escape/js/systems/interactions.js
index 3ee5da59..29aa1940 100644
--- a/public/break_escape/js/systems/interactions.js
+++ b/public/break_escape/js/systems/interactions.js
@@ -965,6 +965,20 @@ export function handleObjectInteraction(sprite) {
return;
}
+ // Handle SIS configuration panel interaction
+ if (sprite.scenarioData.id === 'sis_config_panel' ||
+ sprite.scenarioData.type === 'sis_config_panel' ||
+ sprite.scenarioData.interactionType === 'sis_config_panel') {
+ console.log('SIS config panel interaction:', sprite.scenarioData);
+
+ if (window.startSisConfigThresholdMinigame) {
+ window.startSisConfigThresholdMinigame(sprite);
+ } else {
+ window.gameAlert('SIS configuration minigame unavailable.', 'error', 'Error', 3000);
+ }
+ return;
+ }
+
// Handle the Lockpick Set - pick it up if takeable, or use it if in inventory
if (sprite.scenarioData.type === "lockpick" || sprite.scenarioData.type === "lockpickset") {
// If it's in inventory (marked as non-takeable), just acknowledge it
diff --git a/scenarios/sis02_energy/scenario.json.erb b/scenarios/sis02_energy/scenario.json.erb
index a53943f5..cbc8313e 100644
--- a/scenarios/sis02_energy/scenario.json.erb
+++ b/scenarios/sis02_energy/scenario.json.erb
@@ -36,11 +36,11 @@
# readable notes — analog thermometer, SIS config, NIS form
# timedConversation — Priya opening briefing cutscene
# NPC eventMappings — state-driven global variable progression
+# sis_config_panel — interactive SIS threshold display (MG-03)
#
# PLACEHOLDER — functional stub in place; custom work pending
# esd_pushbutton → lockType:pin (needs MG-01 custom ESD pushbutton interaction)
# hmi_ops_01 → password PC (needs MG-02 SCADA historian trend viewer VM)
-# sis_config_panel → readable text (needs MG-03 interactive SIS threshold display)
# alarm_panel → smartscreen (needs ENG-01 state-reactive alarm panel driver)
# hydrogen_detector → smartscreen (needs ENG-02 timed gas alarm progression)
#
@@ -296,7 +296,7 @@ hmi_password = @random_password # HMI-OPS-01 SCADA workstation password
"order": 6,
"tasks": [
{
- // TODO[MINIGAME]: sis_config_panel — custom SIS threshold viewer MG-03; currently readable text
+ // IMPLEMENTED: sis_config_panel — custom SIS threshold viewer MG-03
"taskId": "read_sis_config",
"title": "Read the SIS configuration panel — check thermal runaway threshold",
"type": "manual",
@@ -887,7 +887,7 @@ hmi_password = @random_password # HMI-OPS-01 SCADA workstation password
"onRead": { "setVariable": { "jump_server_isolated": true } }
},
- // TODO[MINIGAME]: sis_config_panel — interactive SIS threshold display — needs MG-03
+ // IMPLEMENTED: sis_config_panel — interactive SIS threshold display (MG-03)
// PLACEHOLDER: readable smartscreen showing tampered setpoints with amber deviation highlight
{
"type": "smartscreen",
@@ -895,6 +895,40 @@ hmi_password = @random_password # HMI-OPS-01 SCADA workstation password
"name": "SIS Configuration Panel",
"takeable": false,
"readable": true,
+ "minigame": {
+ "title": "SIS CONFIGURATION - BATTERY HALL SIS",
+ "compareTitle": "Compare with Certification Document",
+ "confirmLabel": "Confirm SIS Tamper - Report to Security",
+ "rows": [
+ {
+ "parameter": "THERMAL_RUNAWAY_THRESHOLD",
+ "currentValue": "85C",
+ "certifiedValue": "55C",
+ "status": "AMBER",
+ "lastModified": "03:22 (today)",
+ "modifiedBy": "engineering_access",
+ "detailText": "This value deviates from the IEC 61511 certified baseline. Possible causes: (1) authorised maintenance change requiring recertification, (2) unauthorised modification."
+ },
+ {
+ "parameter": "H2_ALARM_THRESHOLD",
+ "currentValue": "1.2% LEL",
+ "certifiedValue": "1.0% LEL",
+ "status": "AMBER",
+ "lastModified": "03:22 (today)",
+ "modifiedBy": "engineering_access",
+ "detailText": "Hydrogen trip threshold has been raised above certified baseline, reducing early-warning margin."
+ },
+ {
+ "parameter": "MAX_CHARGE_VOLTAGE",
+ "currentValue": "4.32 V/cell",
+ "certifiedValue": "4.25 V/cell",
+ "status": "AMBER",
+ "lastModified": "03:22 (today)",
+ "modifiedBy": "engineering_access",
+ "detailText": "Overcharge protection limit exceeds certified value, increasing thermal risk during charging."
+ }
+ ]
+ },
"observations": "A dedicated display showing the SIS (Safety Instrumented System) configuration. The thermal runaway threshold value is highlighted in amber — a deviation indicator.",
"text": "SAFETY INSTRUMENTED SYSTEM — CONFIGURATION\nAlbion Battery Hall SIS | Firmware: 2.4.1\n\nTHERMAL RUNAWAY PROTECTION:\n THERMAL_RUNAWAY_THRESHOLD: 85°C [AMBER — DEVIATION FROM CERTIFIED]\n Certified baseline: 55°C\n Last modified: 03:22 (today) | Modified by: engineering_access\n\nGAS DETECTION TRIP:\n H2_ALARM_THRESHOLD: 1.2% LEL [AMBER — DEVIATION FROM CERTIFIED]\n Certified baseline: 1.0% LEL\n\nOVERCHARGE PROTECTION:\n MAX_CHARGE_VOLTAGE: 4.32 V/cell [AMBER — DEVIATION FROM CERTIFIED]\n Certified baseline: 4.25 V/cell\n\nFIRMWARE VERSION: 2.4.1 (certified firmware: 2.3.8)\n Patch 2.4.1 status: UNAUTHORISED INSTALLATION\n Note: 2.4.1 was available from vendor for 18 months. Installation here was not via the approved recertification process.\n\nStatus: MULTIPLE SETPOINT DEVIATIONS DETECTED",
"onRead": { "setVariable": { "sis_config_seen": true } }
@@ -917,8 +951,7 @@ hmi_password = @random_password # HMI-OPS-01 SCADA workstation password
"name": "SIS Certification Document (IEC 61511)",
"readable": true,
"takeable": true,
- "text": "SAFETY REQUIREMENTS SPECIFICATION\nAlbion Energy Storage Ltd — Battery Hall SIS\nIEC 61511 SIL 2 Certification — Certified 18 months ago\n\nCERTIFIED OPERATING SETPOINTS (MANDATORY — DO NOT MODIFY WITHOUT RECERTIFICATION):\n THERMAL_RUNAWAY_THRESHOLD: 55°C\n H2_ALARM_THRESHOLD: 1.0% LEL\n MAX_CHARGE_VOLTAGE: 4.25 V/cell\n\nPATCH STATUS:\n SIS Firmware 2.4.1 — available from vendor for 18 months.\n Status: DEFERRED pending recertification budget approval.\n Recertification cost estimate: £180,000 | Duration: 8 weeks offline.\n Risk assessment status: Accepted — 'Low probability; maintain compensating controls.'\n\nANY MODIFICATION to SIS setpoints requires SIL 2 recertification under IEC 61511.\nA modified but uncertified SIS is not a SIS — it is an unvalidated control system.",
- "onRead": { "setVariable": { "sis_tamper_confirmed": true } }
+ "text": "SAFETY REQUIREMENTS SPECIFICATION\nAlbion Energy Storage Ltd — Battery Hall SIS\nIEC 61511 SIL 2 Certification — Certified 18 months ago\n\nCERTIFIED OPERATING SETPOINTS (MANDATORY — DO NOT MODIFY WITHOUT RECERTIFICATION):\n THERMAL_RUNAWAY_THRESHOLD: 55°C\n H2_ALARM_THRESHOLD: 1.0% LEL\n MAX_CHARGE_VOLTAGE: 4.25 V/cell\n\nPATCH STATUS:\n SIS Firmware 2.4.1 — available from vendor for 18 months.\n Status: DEFERRED pending recertification budget approval.\n Recertification cost estimate: £180,000 | Duration: 8 weeks offline.\n Risk assessment status: Accepted — 'Low probability; maintain compensating controls.'\n\nANY MODIFICATION to SIS setpoints requires SIL 2 recertification under IEC 61511.\nA modified but uncertified SIS is not a SIS — it is an unvalidated control system."
},
{
"type": "notes2",
From 50f7866f4567ba8caa429d0c8d7985ff7b9c5e62 Mon Sep 17 00:00:00 2001
From: alixthegreat <146326639+alixxhiscock@users.noreply.github.com>
Date: Sun, 12 Apr 2026 14:53:48 +0100
Subject: [PATCH 3/4] fix merge conflict in interactions.js
---
public/break_escape/js/systems/interactions.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/public/break_escape/js/systems/interactions.js b/public/break_escape/js/systems/interactions.js
index 9e559b63..dffc81d8 100644
--- a/public/break_escape/js/systems/interactions.js
+++ b/public/break_escape/js/systems/interactions.js
@@ -975,6 +975,10 @@ export function handleObjectInteraction(sprite) {
window.startSisConfigThresholdMinigame(sprite);
} else {
window.gameAlert('SIS configuration minigame unavailable.', 'error', 'Error', 3000);
+ }
+ return;
+ }
+
// Handle ESD pushbutton by object-type interaction
if (sprite.scenarioData.type === 'esd_button' ||
sprite.scenarioData.interactionType === 'esd_button') {
From 4bafb0bf20fed30f8f238e41786049c9a1a0255b Mon Sep 17 00:00:00 2001
From: alixthegreat <146326639+alixxhiscock@users.noreply.github.com>
Date: Sun, 12 Apr 2026 16:01:06 +0100
Subject: [PATCH 4/4] Review of sis configuration threshold and minor changes
---
.../sis_configuration_threshold_review.md | 116 ++++++++++++++++++
.../sis-config-threshold-minigame.js | 23 ++--
scenarios/sis02_energy/scenario.json.erb | 14 ++-
3 files changed, 138 insertions(+), 15 deletions(-)
create mode 100644 planning_notes/sis-configuration-threshold/sis_configuration_threshold_review.md
diff --git a/planning_notes/sis-configuration-threshold/sis_configuration_threshold_review.md b/planning_notes/sis-configuration-threshold/sis_configuration_threshold_review.md
new file mode 100644
index 00000000..1cc860dc
--- /dev/null
+++ b/planning_notes/sis-configuration-threshold/sis_configuration_threshold_review.md
@@ -0,0 +1,116 @@
+# SIS Configuration Threshold Review (2026-04-12)
+
+## Scope
+
+Review current SIS configuration threshold implementation against planning sources under `planning_notes/sis_scenarios`.
+
+## Planning Sources Reviewed
+
+- `planning_notes/sis_scenarios/case_2_energy_game_design/minigame_planning.md`
+- `planning_notes/sis_scenarios/case_2_energy_game_design/development_tasks.csv`
+- Supplemental implementation alignment notes:
+ - `planning_notes/sis-configuration-threshold/sis_configuration_threshold_implementation_plan.md`
+
+## Implementation Files Reviewed
+
+- `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js`
+- `public/break_escape/css/sis-config-threshold-minigame.css`
+- `public/break_escape/js/minigames/index.js`
+- `public/break_escape/js/systems/interactions.js`
+- `scenarios/sis02_energy/scenario.json.erb`
+
+## Executive Summary
+
+Implementation is mostly in place and wired end-to-end (scene registration, object routing, UI, row-detail modal, compare overlay, and confirm flow). The prior certification-document bypass has been removed, and the progression now follows an explicit two-step model: review certification evidence, then confirm tamper.
+
+## Matches
+
+1. Minigame implemented as HTML/CSS interactive panel (planned MG-03/MG-02 equivalent).
+ - Evidence: `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js`
+ - Evidence: `public/break_escape/css/sis-config-threshold-minigame.css`
+ - Planning: `planning_notes/sis_scenarios/case_2_energy_game_design/minigame_planning.md:87-99`
+
+2. Panel interaction is wired from `sis_config_panel` object and launches the SIS minigame.
+ - Evidence: `public/break_escape/js/systems/interactions.js:969-975`
+ - Evidence: `public/break_escape/js/minigames/index.js:137,155`
+ - Planning: `planning_notes/sis_scenarios/case_2_energy_game_design/minigame_planning.md:90`
+
+3. Scenario object carries minigame data contract (title, rows, compareTitle, confirmLabel).
+ - Evidence: `scenarios/sis02_energy/scenario.json.erb:1021-1029`
+ - Planning: `planning_notes/sis-configuration-threshold/sis_configuration_threshold_implementation_plan.md:146-166`
+
+4. Row-level detail expansion for non-GREEN rows is implemented.
+ - Evidence: `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:68-85,112-119,152-170`
+ - Planning: `planning_notes/sis_scenarios/case_2_energy_game_design/minigame_planning.md:102`
+
+5. Compare overlay exists and is disabled when certification evidence is missing.
+ - Evidence: `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:65,99,124-128,171-201`
+ - Planning: `planning_notes/sis_scenarios/case_2_energy_game_design/minigame_planning.md:103,116`
+
+6. Confirm action exists and sets `sis_tamper_confirmed = true`.
+ - Evidence: `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:229-231`
+ - Planning: `planning_notes/sis_scenarios/case_2_energy_game_design/minigame_planning.md:104`
+
+7. `sis_config_seen` is set when panel opens; objective task completion wiring is present.
+ - Evidence: `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:56`
+ - Evidence: `scenarios/sis02_energy/scenario.json.erb:517-521`
+ - Planning: `planning_notes/sis-configuration-threshold/sis_configuration_threshold_implementation_plan.md:88,93,177-179`
+
+## Mismatches
+
+No active functional mismatches identified for the implemented SIS minigame flow after the latest changes.
+
+### Resolved During Review
+
+1. Certification document read no longer bypasses tamper confirmation.
+ - Current behavior: cert document now sets `sis_certification_seen`, not `sis_tamper_confirmed`.
+ - Evidence: `scenarios/sis02_energy/scenario.json.erb:93,526,1098`
+ - Confirm remains explicit in minigame action: `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:234`
+
+2. Comparison gate now supports global-variable gating via `sis_certification_seen`.
+ - Evidence: `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:139`
+ - Compare gating now uses the global-variable check directly.
+
+3. `en002_claim_assessed` is intentionally mapped from confirmed tamper (`sis_tamper_confirmed`) via scenario event wiring.
+ - Evidence: `scenarios/sis02_energy/scenario.json.erb:533-536`
+ - Decision: accepted implementation approach.
+
+## Accepted Design Deviation
+
+1. Main table intentionally omits a visible "certified baseline" column so the certification document and compare action retain investigative value.
+ - Current behavior: certified values are shown in compare overlay, not in the default table.
+ - Evidence (current columns): `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:89-91`
+ - Evidence (certified values in compare overlay): `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:181`
+ - Status: accepted by design decision; no change required unless design intent changes.
+
+## Recommended Next Changes (Priority Order)
+
+1. Run end-to-end in-game validation of the intended sequence.
+ - Sequence to verify: `sis_config_seen` (panel read) -> `sis_certification_seen` (cert doc read) -> compare enabled -> `sis_tamper_confirmed` (confirm action) -> `en002_claim_assessed` event mapping.
+ - Evidence wiring: `scenarios/sis02_energy/scenario.json.erb:519,526,533-536`; `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:56,138,234`.
+
+## Follow-up Q&A Verification (2026-04-12)
+
+1. Is the cert-doc bypass still in place?
+ - No. Cert doc read now sets `sis_certification_seen` and no longer sets `sis_tamper_confirmed`: `scenarios/sis02_energy/scenario.json.erb:1098`.
+
+2. Why not show certified values in the base table?
+ - Accepted design rationale: keeping certified values in compare mode preserves the purpose of retrieving the certification document.
+
+3. Does `en002_claim_assessed` get set at all?
+ - Yes, indirectly. Event mapping on `global_variable_changed:sis_tamper_confirmed` sets `en002_claim_assessed = true`: `scenarios/sis02_energy/scenario.json.erb:533-536`.
+ - It is not set directly in `applyConfirm()`: `public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js:234`.
+
+4. Is there a `sis_certification_seen` or `sis_cert_reviewed` global set on cert-doc view?
+ - Yes. `sis_certification_seen` now exists in scenario globals and is set on cert-doc read.
+ - Evidence: `scenarios/sis02_energy/scenario.json.erb:93,1098`.
+
+## Current Assessment
+
+- Functional readiness: Good
+- Design/spec conformance: Good
+- Progression integrity risk: Low (pending final in-game validation)
+
+## Validation Status
+
+- End-to-end playthrough verification: Pending user run
diff --git a/public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js b/public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js
index 067f1113..55d55b48 100644
--- a/public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js
+++ b/public/break_escape/js/minigames/sis-config-threshold/sis-config-threshold-minigame.js
@@ -30,8 +30,6 @@ const DEFAULT_ROWS = [
}
];
-const CERTIFICATION_DOC_NAME = 'SIS Certification Document (IEC 61511)';
-
function normalizeStatus(status) {
return String(status || 'GREEN').toUpperCase();
}
@@ -137,16 +135,16 @@ export class SisConfigThresholdMinigame extends MinigameScene {
}
hasCertificationDoc() {
- const items = window.inventory?.items || [];
- const hasInventoryDoc = items.some((item) => {
- const name = item?.scenarioData?.name || item?.name || '';
- return String(name).trim() === CERTIFICATION_DOC_NAME;
- });
+ if (window.gameState?.globalVariables?.sis_certification_seen === true) {
+ return true;
+ }
- if (hasInventoryDoc) return true;
+ const certTask = window.objectivesManager?.taskIndex?.find_certification_doc;
+ if (certTask?.status === 'completed') {
+ return true;
+ }
- const notes = window.gameState?.notes || [];
- return notes.some((note) => String(note?.title || '').trim() === CERTIFICATION_DOC_NAME);
+ return false;
}
showDetail(row) {
@@ -247,7 +245,6 @@ export class SisConfigThresholdMinigame extends MinigameScene {
setScenarioGlobal(name, value) {
if (window.npcManager?.setGlobalVariable) {
window.npcManager.setGlobalVariable(name, value);
- return;
}
if (!window.gameState) window.gameState = {};
@@ -256,6 +253,10 @@ export class SisConfigThresholdMinigame extends MinigameScene {
const oldValue = window.gameState.globalVariables[name];
window.gameState.globalVariables[name] = value;
+ if (window.npcConversationStateManager) {
+ window.npcConversationStateManager.broadcastGlobalVariableChange(name, value, null);
+ }
+
if (window.eventDispatcher) {
window.eventDispatcher.emit(`global_variable_changed:${name}`, {
name,
diff --git a/scenarios/sis02_energy/scenario.json.erb b/scenarios/sis02_energy/scenario.json.erb
index 4a281900..698d2891 100644
--- a/scenarios/sis02_energy/scenario.json.erb
+++ b/scenarios/sis02_energy/scenario.json.erb
@@ -90,6 +90,7 @@ hmi_password = @random_password # HMI-OPS-01 SCADA workstation password
"network_isolated": false,
"sis_config_seen": false,
+ "sis_certification_seen": false,
"sis_tamper_confirmed": false,
"en002_claim_assessed": false,
@@ -521,11 +522,17 @@ hmi_password = @random_password # HMI-OPS-01 SCADA workstation password
"completeTask": "read_sis_config"
},
{
- // find_certification_doc task completes and EN-002 claim assessed when cert doc confirms tamper
+ // find_certification_doc task completes when SIS certification evidence is reviewed
+ "eventPattern": "global_variable_changed:sis_certification_seen",
+ "condition": "value === true",
+ "onceOnly": true,
+ "completeTask": "find_certification_doc"
+ },
+ {
+ // EN-002 claim assessed when player confirms SIS tamper
"eventPattern": "global_variable_changed:sis_tamper_confirmed",
"condition": "value === true",
"onceOnly": true,
- "completeTask": "find_certification_doc",
"setGlobal": { "en002_claim_assessed": true }
},
{
@@ -1083,12 +1090,11 @@ hmi_password = @random_password # HMI-OPS-01 SCADA workstation password
"name": "SIS Certification Document (IEC 61511)",
"readable": true,
"takeable": true,
- "text": "SAFETY REQUIREMENTS SPECIFICATION\nAlbion Energy Storage Ltd — Battery Hall SIS\nIEC 61511 SIL 2 Certification — Certified 18 months ago\n\nCERTIFIED OPERATING SETPOINTS (MANDATORY — DO NOT MODIFY WITHOUT RECERTIFICATION):\n THERMAL_RUNAWAY_THRESHOLD: 55°C\n H2_ALARM_THRESHOLD: 1.0% LEL\n MAX_CHARGE_VOLTAGE: 4.25 V/cell\n\nPATCH STATUS:\n SIS Firmware 2.4.1 — available from vendor for 18 months.\n Status: DEFERRED pending recertification budget approval.\n Recertification cost estimate: £180,000 | Duration: 8 weeks offline.\n Risk assessment status: Accepted — 'Low probability; maintain compensating controls.'\n\nANY MODIFICATION to SIS setpoints requires SIL 2 recertification under IEC 61511.\nA modified but uncertified SIS is not a SIS — it is an unvalidated control system."
"puzzle_graph_role": "clue",
"puzzle_graph_aim": "investigate_sis",
"puzzle_graph_reveals": "Certified THERMAL_RUNAWAY_THRESHOLD: 55°C — confirms SIS tamper; SIS firmware patch deferred 18 months; £180k recertification cost cited as barrier",
"text": "SAFETY REQUIREMENTS SPECIFICATION\nAlbion Energy Storage Ltd — Battery Hall SIS\nIEC 61511 SIL 2 Certification — Certified 18 months ago\n\nCERTIFIED OPERATING SETPOINTS (MANDATORY — DO NOT MODIFY WITHOUT RECERTIFICATION):\n THERMAL_RUNAWAY_THRESHOLD: 55°C\n H2_ALARM_THRESHOLD: 1.0% LEL\n MAX_CHARGE_VOLTAGE: 4.25 V/cell\n\nPATCH STATUS:\n SIS Firmware 2.4.1 — available from vendor for 18 months.\n Status: DEFERRED pending recertification budget approval.\n Recertification cost estimate: £180,000 | Duration: 8 weeks offline.\n Risk assessment status: Accepted — 'Low probability; maintain compensating controls.'\n\nANY MODIFICATION to SIS setpoints requires SIL 2 recertification under IEC 61511.\nA modified but uncertified SIS is not a SIS — it is an unvalidated control system.",
- "onRead": { "setVariable": { "sis_tamper_confirmed": true } }
+ "onRead": { "setVariable": { "sis_certification_seen": true } }
},
{
"type": "notes2",