@bramas/simulant-ui 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -205,6 +205,15 @@ export const SimulatorApp = (props) => {
205
205
  const schema = editorSchema();
206
206
  return schema ? formValues(schema, projectUserSettings()) : projectUserSettings() ?? {};
207
207
  });
208
+ const settingsWarnings = createMemo(() => {
209
+ projectRevision();
210
+ try {
211
+ return Projects[project()].settingsWarnings?.(projectUserSettings()) ?? [];
212
+ }
213
+ catch (e) {
214
+ return [`Could not check initial settings: ${e instanceof Error ? e.message : String(e)}`];
215
+ }
216
+ });
208
217
  /** The task's verdict on the current configuration, with what it means under the task's goal. */
209
218
  const verdict = createMemo(() => {
210
219
  redrawTick();
@@ -458,10 +467,6 @@ export const SimulatorApp = (props) => {
458
467
  {notice().text}
459
468
  </pre>)}
460
469
  </Show>
461
- <Show when={setupLog()}>
462
- <div class="sim-notice sim-error"><mark>{setupLog()}</mark></div>
463
- </Show>
464
-
465
470
  <Show when={modelShown() && description()}>
466
471
  {d => <ModelView description={d()} simulation={project()} onCopyLink={() => copy(`${shareLink(effectiveSettings(), currentPath())}#model`)}/>}
467
472
  </Show>
@@ -529,7 +534,7 @@ export const SimulatorApp = (props) => {
529
534
  </div>
530
535
 
531
536
  <div class="sim-panels">
532
- <section class="sim-card">
537
+ <section class="sim-card sim-settings">
533
538
  <h3>
534
539
  Settings
535
540
  <span class="sim-spacer" style={{ flex: 1 }}/>
@@ -538,6 +543,16 @@ export const SimulatorApp = (props) => {
538
543
  <Show when={editorSchema()} keyed>
539
544
  {schema => (<GenericEditor schema={schema} value={projectUserSettings()} onInput={(v) => batch(() => { setProjectUserSettings(v); goTo([0]); })}/>)}
540
545
  </Show>
546
+ <Show when={setupLog()}>
547
+ <div class="sim-notice sim-error sim-settings-feedback" role="alert"><mark>{setupLog()}</mark></div>
548
+ </Show>
549
+ <Show when={!setupLog() && settingsWarnings().length > 0}>
550
+ <div class="sim-notice sim-settings-warning sim-settings-feedback" role="alert">
551
+ <strong>Initial settings warning</strong>
552
+ <For each={settingsWarnings()}>{warning => <div>{warning}</div>}</For>
553
+ <div>You can still explore this execution. Checks over the declared domains do not cover settings outside them.</div>
554
+ </div>
555
+ </Show>
541
556
  </section>
542
557
  <section class="sim-card">
543
558
  <h3>Saved settings</h3>
@@ -182,10 +182,13 @@ export function describeExperiment(exp, sources, revision, lean) {
182
182
  },
183
183
  {
184
184
  label: 'Synchrony',
185
- value: model.round === 'fsync' ? 'FSYNC (fully synchronous)' : 'SSYNC (semi-synchronous)',
185
+ value: model.round === 'fsync' ? 'FSYNC (fully synchronous)' : model.round === 'sequential' ? 'Sequential (fair)' : 'SSYNC (semi-synchronous)',
186
186
  note: model.round === 'fsync'
187
187
  ? 'Every agent able to act is activated in every round.'
188
- : 'In every round, the adversary activates a nonempty set of the agents able to act. Only fair executions count: every agent that keeps acting is activated infinitely often.',
188
+ : (model.round === 'sequential'
189
+ ? 'In every round, the adversary activates exactly one agent able to act (or none if no agent can act). '
190
+ : 'In every round, the adversary activates a nonempty set of the agents able to act. ')
191
+ + 'Only fair executions count: every agent that keeps acting is activated infinitely often.',
189
192
  refs: modelRef('round'),
190
193
  },
191
194
  {
@@ -281,14 +284,14 @@ export function describeExperiment(exp, sources, revision, lean) {
281
284
  {
282
285
  label: 'Goal',
283
286
  value: GOALS[task.goal].formula,
284
- note: `${model.round === 'ssync' ? 'Over every fair execution' : 'Over every execution'}: ${GOALS[task.goal].text}.`,
287
+ note: `${model.round !== 'fsync' ? 'Over every fair execution' : 'Over every execution'}: ${GOALS[task.goal].text}.`,
285
288
  refs: refTo('goal', task.name),
286
289
  },
287
290
  {
288
291
  label: 'Adversary',
289
292
  value: 'Unrestricted',
290
293
  note: 'No fairness assumption forces an adversary choice (a hazard to appear, a missing edge to return)'
291
- + (model.round === 'ssync' ? ', apart from fair activation.' : '.'),
294
+ + (model.round !== 'fsync' ? ', apart from fair activation.' : '.'),
292
295
  },
293
296
  ],
294
297
  },
@@ -327,10 +330,12 @@ export function describeExperiment(exp, sources, revision, lean) {
327
330
  hook('beforeLook', 'Components update their state, all reading the same configuration.'),
328
331
  {
329
332
  phase: 'Activation',
330
- what: (model.round === 'fsync' ? 'Every agent able to act is activated.' : 'A nonempty set of the agents able to act is activated.')
333
+ what: (model.round === 'fsync' ? 'Every agent able to act is activated.'
334
+ : model.round === 'sequential' ? 'Exactly one agent able to act is activated (none if no agent can act).'
335
+ : 'A nonempty set of the agents able to act is activated.')
331
336
  + (model.frame.kind === 'dynamicReflection' ? " Each activated agent's orientation is chosen." : ''),
332
337
  choices: [
333
- ...(model.round === 'ssync' ? ['activated agents (fair)'] : []),
338
+ ...(model.round !== 'fsync' ? ['activated agents (fair)'] : []),
334
339
  ...(model.frame.kind === 'dynamicReflection' ? ['orientations'] : []),
335
340
  ],
336
341
  },
@@ -1,4 +1,4 @@
1
- import { parameterValues, System } from "@bramas/simulant-engine/system";
1
+ import { parameterDomainViolations, parameterValues, System } from "@bramas/simulant-engine/system";
2
2
  import { checkFirstBranch, checkSetting, checkSettings, stateGraph } from "@bramas/simulant-engine/check";
3
3
  import { formatDiagnostic } from "@bramas/simulant-vite-plugin/module";
4
4
  import { isRenderer } from "../renderers/define.js";
@@ -239,6 +239,11 @@ export function simProject(module, experiment, opts = {}) {
239
239
  setup: setup,
240
240
  execute: (model) => simExecution(model.system),
241
241
  normalizeSettings,
242
+ settingsWarnings: settings => {
243
+ const params = paramsOf(settings);
244
+ return parameterDomainViolations(need().exp, params)
245
+ .map(name => `${name} = ${JSON.stringify(params[name])} is outside its declared parameter domain.`);
246
+ },
242
247
  subscribe: listener => {
243
248
  listeners.add(listener);
244
249
  return () => { listeners.delete(listener); };
@@ -395,6 +395,15 @@
395
395
  border-color: var(--sim-failure);
396
396
  }
397
397
 
398
+ .sim-settings-feedback {
399
+ font-family: inherit;
400
+ margin: 0;
401
+ }
402
+
403
+ .sim-settings-warning {
404
+ white-space: normal;
405
+ }
406
+
398
407
  .sim-toast {
399
408
  position: fixed;
400
409
  bottom: 1.25rem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bramas/simulant-ui",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "license": "CECILL-B",
6
6
  "type": "module",
@@ -31,11 +31,11 @@
31
31
  }
32
32
  },
33
33
  "dependencies": {
34
- "@bramas/simulant-core": "0.1.0",
35
- "@bramas/simulant-lean-gen": "0.1.0",
36
- "@bramas/simulant-vite-plugin": "0.1.0",
37
- "@bramas/simulant-engine": "0.1.0",
38
- "@bramas/simulant-lang": "0.1.0"
34
+ "@bramas/simulant-lang": "0.1.1",
35
+ "@bramas/simulant-lean-gen": "0.1.1",
36
+ "@bramas/simulant-engine": "0.1.1",
37
+ "@bramas/simulant-core": "0.1.1",
38
+ "@bramas/simulant-vite-plugin": "0.1.1"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "solid-js": "^1.9.3"
@@ -223,6 +223,15 @@ export const SimulatorApp: Component<SimulatorAppProps> = (props) => {
223
223
  return schema ? formValues(schema, projectUserSettings()) : projectUserSettings() ?? {};
224
224
  });
225
225
 
226
+ const settingsWarnings = createMemo(() => {
227
+ projectRevision();
228
+ try {
229
+ return Projects[project()].settingsWarnings?.(projectUserSettings()) ?? [];
230
+ } catch (e) {
231
+ return [`Could not check initial settings: ${e instanceof Error ? e.message : String(e)}`];
232
+ }
233
+ });
234
+
226
235
  /** The task's verdict on the current configuration, with what it means under the task's goal. */
227
236
  const verdict = createMemo(() => {
228
237
  redrawTick();
@@ -469,10 +478,6 @@ export const SimulatorApp: Component<SimulatorAppProps> = (props) => {
469
478
  </pre>
470
479
  )}
471
480
  </Show>
472
- <Show when={setupLog()}>
473
- <div class="sim-notice sim-error"><mark>{setupLog()}</mark></div>
474
- </Show>
475
-
476
481
  <Show when={modelShown() && description()}>
477
482
  {d => <ModelView description={d()} simulation={project()} onCopyLink={() => copy(`${shareLink(effectiveSettings(), currentPath())}#model`)} />}
478
483
  </Show>
@@ -553,7 +558,7 @@ export const SimulatorApp: Component<SimulatorAppProps> = (props) => {
553
558
  </div>
554
559
 
555
560
  <div class="sim-panels">
556
- <section class="sim-card">
561
+ <section class="sim-card sim-settings">
557
562
  <h3>
558
563
  Settings
559
564
  <span class="sim-spacer" style={{ flex: 1 }} />
@@ -568,6 +573,16 @@ export const SimulatorApp: Component<SimulatorAppProps> = (props) => {
568
573
  />
569
574
  )}
570
575
  </Show>
576
+ <Show when={setupLog()}>
577
+ <div class="sim-notice sim-error sim-settings-feedback" role="alert"><mark>{setupLog()}</mark></div>
578
+ </Show>
579
+ <Show when={!setupLog() && settingsWarnings().length > 0}>
580
+ <div class="sim-notice sim-settings-warning sim-settings-feedback" role="alert">
581
+ <strong>Initial settings warning</strong>
582
+ <For each={settingsWarnings()}>{warning => <div>{warning}</div>}</For>
583
+ <div>You can still explore this execution. Checks over the declared domains do not cover settings outside them.</div>
584
+ </div>
585
+ </Show>
571
586
  </section>
572
587
  <section class="sim-card">
573
588
  <h3>Saved settings</h3>
@@ -187,10 +187,13 @@ export function describeExperiment(exp: Experiment, sources: Record<string, stri
187
187
  },
188
188
  {
189
189
  label: 'Synchrony',
190
- value: model.round === 'fsync' ? 'FSYNC (fully synchronous)' : 'SSYNC (semi-synchronous)',
190
+ value: model.round === 'fsync' ? 'FSYNC (fully synchronous)' : model.round === 'sequential' ? 'Sequential (fair)' : 'SSYNC (semi-synchronous)',
191
191
  note: model.round === 'fsync'
192
192
  ? 'Every agent able to act is activated in every round.'
193
- : 'In every round, the adversary activates a nonempty set of the agents able to act. Only fair executions count: every agent that keeps acting is activated infinitely often.',
193
+ : (model.round === 'sequential'
194
+ ? 'In every round, the adversary activates exactly one agent able to act (or none if no agent can act). '
195
+ : 'In every round, the adversary activates a nonempty set of the agents able to act. ')
196
+ + 'Only fair executions count: every agent that keeps acting is activated infinitely often.',
194
197
  refs: modelRef('round'),
195
198
  },
196
199
  {
@@ -285,14 +288,14 @@ export function describeExperiment(exp: Experiment, sources: Record<string, stri
285
288
  {
286
289
  label: 'Goal',
287
290
  value: GOALS[task.goal].formula,
288
- note: `${model.round === 'ssync' ? 'Over every fair execution' : 'Over every execution'}: ${GOALS[task.goal].text}.`,
291
+ note: `${model.round !== 'fsync' ? 'Over every fair execution' : 'Over every execution'}: ${GOALS[task.goal].text}.`,
289
292
  refs: refTo('goal', task.name),
290
293
  },
291
294
  {
292
295
  label: 'Adversary',
293
296
  value: 'Unrestricted',
294
297
  note: 'No fairness assumption forces an adversary choice (a hazard to appear, a missing edge to return)'
295
- + (model.round === 'ssync' ? ', apart from fair activation.' : '.'),
298
+ + (model.round !== 'fsync' ? ', apart from fair activation.' : '.'),
296
299
  },
297
300
  ],
298
301
  },
@@ -333,10 +336,12 @@ export function describeExperiment(exp: Experiment, sources: Record<string, stri
333
336
  hook('beforeLook', 'Components update their state, all reading the same configuration.'),
334
337
  {
335
338
  phase: 'Activation',
336
- what: (model.round === 'fsync' ? 'Every agent able to act is activated.' : 'A nonempty set of the agents able to act is activated.')
339
+ what: (model.round === 'fsync' ? 'Every agent able to act is activated.'
340
+ : model.round === 'sequential' ? 'Exactly one agent able to act is activated (none if no agent can act).'
341
+ : 'A nonempty set of the agents able to act is activated.')
337
342
  + (model.frame.kind === 'dynamicReflection' ? " Each activated agent's orientation is chosen." : ''),
338
343
  choices: [
339
- ...(model.round === 'ssync' ? ['activated agents (fair)'] : []),
344
+ ...(model.round !== 'fsync' ? ['activated agents (fair)'] : []),
340
345
  ...(model.frame.kind === 'dynamicReflection' ? ['orientations'] : []),
341
346
  ],
342
347
  },
@@ -6,7 +6,7 @@
6
6
  * `draw`, the algorithm view from the algorithm's source and line table.
7
7
  */
8
8
  import type { Experiment, Type } from '@bramas/simulant-lang/ir';
9
- import { parameterValues, System } from '@bramas/simulant-engine/system';
9
+ import { parameterDomainViolations, parameterValues, System } from '@bramas/simulant-engine/system';
10
10
  import { checkFirstBranch, checkSetting, checkSettings, stateGraph, type CheckResult } from '@bramas/simulant-engine/check';
11
11
  import type { EditorField, EditorSchema } from '@bramas/simulant-core/types/editor-schema';
12
12
  import type { AlgorithmSource, CheckOptions, ModelDescription, ProjectType, ProjectUpdate } from '@bramas/simulant-core/types/project';
@@ -269,6 +269,11 @@ export function simProject(module: SimSources, experiment: string, opts: SimProj
269
269
  setup: setup as ProjectType<any, any>['setup'],
270
270
  execute: (model: SimModel) => simExecution(model.system),
271
271
  normalizeSettings,
272
+ settingsWarnings: settings => {
273
+ const params = paramsOf(settings);
274
+ return parameterDomainViolations(need().exp, params)
275
+ .map(name => `${name} = ${JSON.stringify(params[name])} is outside its declared parameter domain.`);
276
+ },
272
277
  subscribe: listener => {
273
278
  listeners.add(listener);
274
279
  return () => { listeners.delete(listener); };
package/src/simulator.css CHANGED
@@ -395,6 +395,15 @@
395
395
  border-color: var(--sim-failure);
396
396
  }
397
397
 
398
+ .sim-settings-feedback {
399
+ font-family: inherit;
400
+ margin: 0;
401
+ }
402
+
403
+ .sim-settings-warning {
404
+ white-space: normal;
405
+ }
406
+
398
407
  .sim-toast {
399
408
  position: fixed;
400
409
  bottom: 1.25rem;