From 5628b0bc12a1a0f69a61df470a33334642a50f43 Mon Sep 17 00:00:00 2001
From: Valentin Perrelle <valentin.perrelle@cea.fr>
Date: Thu, 6 Oct 2022 21:52:02 +0200
Subject: [PATCH] [Dome] Use only safe decoders and throw exceptions when the
 decoded json mismatches

- stricter conversion of tuples (checks list size)
- stricter conversion of integers (checks that there is no fractional part)
- jCatch only catches JsonErrors
- more detailed error messages to debug the server interface
- jUnion works more often
- fixed several mistyping
---
 ivette/src/dome/renderer/data/json.ts         | 495 +++++++++++-------
 ivette/src/dome/renderer/data/settings.ts     |  28 +-
 ivette/src/dome/renderer/dome.tsx             |   2 +-
 ivette/src/dome/renderer/table/views.tsx      |   4 +-
 ivette/src/frama-c/kernel/ASTview.tsx         |   3 +-
 ivette/src/frama-c/kernel/api/ast/index.ts    | 171 +++---
 ivette/src/frama-c/kernel/api/data/index.ts   |  31 +-
 .../src/frama-c/kernel/api/project/index.ts   |  29 +-
 .../frama-c/kernel/api/properties/index.ts    |  72 +--
 .../src/frama-c/kernel/api/services/index.ts  |  77 ++-
 ivette/src/frama-c/plugins/dive/api/index.ts  | 153 ++----
 .../frama-c/plugins/eva/api/general/index.ts  | 222 +++-----
 .../frama-c/plugins/eva/api/values/index.ts   |  91 ++--
 .../plugins/pivot/api/general/index.ts        |  10 +-
 .../plugins/studia/api/studia/index.ts        |  24 +-
 ivette/src/frama-c/server.ts                  |   4 +-
 ivette/src/renderer/Laboratory.tsx            |   4 +-
 src/plugins/api-generator/api_generator.ml    |  93 ++--
 src/plugins/eva/api/general_requests.ml       |   2 +-
 src/plugins/eva/api/values_request.ml         |   2 +-
 src/plugins/server/data.ml                    |  21 +-
 src/plugins/server/data.mli                   |   1 -
 src/plugins/server/package.ml                 |  19 +-
 src/plugins/server/package.mli                |   8 +-
 src/plugins/server/server_doc.ml              |   6 +-
 25 files changed, 671 insertions(+), 901 deletions(-)

diff --git a/ivette/src/dome/renderer/data/json.ts b/ivette/src/dome/renderer/data/json.ts
index 1d0f78cc81d..60f59d780f7 100644
--- a/ivette/src/dome/renderer/data/json.ts
+++ b/ivette/src/dome/renderer/data/json.ts
@@ -42,6 +42,20 @@ export type json =
 
 export type jobject = { [key: string]: json };
 
+
+/* Parsing exceptions.
+   Stores a string telling what was expected and a json of what have been
+   given */
+
+class JsonError extends Error {
+  expected = '';
+  constructor(expected : string, given : json) {
+    super(`expected ${expected} but given ${given}`);
+    this.name = this.constructor.name;
+    this.expected = expected;
+  }
+}
+
 /**
    Parse without _revivals_.
    Returned data is guaranteed to have only [[json]] type.
@@ -53,9 +67,15 @@ export function parse(text: string, noError = false): json {
   if (noError) {
     try {
       return JSON.parse(text);
-    } catch (err) {
-      D.error('Invalid format:', err);
-      return undefined;
+    }
+    catch (err) {
+      if (err instanceof JsonError) {
+        D.error(err);
+        return undefined;
+      }
+      else {
+        throw err;
+      }
     }
   } else
     return JSON.parse(text);
@@ -76,21 +96,15 @@ export function pretty(js: any): string {
 }
 
 // --------------------------------------------------------------------------
-// --- SAFE Decoder
+// --- Decoder & Encoder types
 // --------------------------------------------------------------------------
 
 /** Decoder for values of type `D`.
     You can abbreviate `Safe<D | undefined>` with `Loose<D>`. */
-export interface Safe<D> {
+export interface Decoder<D> {
   (js?: json): D;
 }
 
-/** Decoder for values of type `D`, if any.
-    Same as `Safe<D | undefined>`. */
-export interface Loose<D> {
-  (js?: json): D | undefined;
-}
-
 /**
    Encoder for value of type `D`.
    In most cases, you only need [[identity]].
@@ -106,162 +120,181 @@ export function identity<A>(v: A): A { return v; }
 // --- Primitives
 // --------------------------------------------------------------------------
 
-/** 'null' or 'undefined'. */
-export const jNull: Loose<null> = (js: json) =>
-  js === null ? null : undefined;
+/** 'null' or throws JsonError. */
+export const jNull: Decoder<null> = (js: json) => {
+  if (js === null) {
+    return null;
+   }
+   else {
+    throw new JsonError("null", js);
+   }
+};
 
 /** Identity. */
-export const jAny: Safe<json> = (js: json) => js;
+export const jAny: Decoder<json> = (js: json) => js;
 
-/** JSON Object. */
-export const jObj: Loose<jobject> = (js: json) => (
-  typeof js === 'object' && !Array.isArray(js) && js !== null ? js : undefined
-);
+/** JSON Object or throws JsonError. */
+export const jObj: Decoder<jobject> = (js: json) => {
+  if (typeof js === 'object' && !Array.isArray(js) && js !== null) {
+    return js;
+  }
+  else {
+    throw new JsonError("object", js);
+  }
+};
 
-/** Primitive JSON number or `undefined`. */
-export const jNumber: Loose<number> = (js: json) => (
-  typeof js === 'number' && !Number.isNaN(js) ? js : undefined
-);
+/** Primitive JSON number or throws JsonError. */
+export const jNumber: Decoder<number> = (js: json) => {
+  if (typeof js === 'number' && !Number.isNaN(js)) {
+    return js;
+  }
+  else {
+    throw new JsonError("object", js);
+  }
+};
 
-/** Primitive JSON number, rounded to integer, or `undefined`. */
-export const jInt: Loose<number> = (js: json) => (
-  typeof js === 'number' && !Number.isNaN(js) ? Math.round(js) : undefined
-);
+/** Primitive JSON number if it is an integer or throws JsonError. */
+export const jInt: Decoder<number> = (js: json) => {
+  if (typeof js === 'number' && Number.isInteger(js)) {
+    return js;
+  }
+  else {
+    throw new JsonError("integer", js); 
+  }
+};
 
 /** Primitive JSON number or `0`. */
-export const jZero: Safe<number> = (js: json) => (
+export const jZero: Decoder<number> = (js: json) => (
   typeof js === 'number' && !Number.isNaN(js) ? js : 0
 );
 
-/** Primitive JSON boolean or `undefined`. */
-export const jBoolean: Loose<boolean> = (js: json) => (
-  typeof js === 'boolean' ? js : undefined
-);
+/** Primitive JSON boolean or throws JsonError. */
+export const jBoolean: Decoder<boolean> = (js: json) => {
+  if (typeof js === 'boolean') {
+    return js;
+  }
+  else {
+    throw new JsonError("boolean", js); 
+  }
+};
 
 /** Primitive JSON boolean or `true`. */
-export const jTrue: Safe<boolean> = (js: json) => (
+export const jTrue: Decoder<boolean> = (js: json) => (
   typeof js === 'boolean' ? js : true
 );
 
 /** Primitive JSON boolean or `false`. */
-export const jFalse: Safe<boolean> = (js: json) => (
+export const jFalse: Decoder<boolean> = (js: json) => (
   typeof js === 'boolean' ? js : false
 );
 
-/** Primitive JSON string or `undefined`. */
-export const jString: Loose<string> = (js: json) => (
-  typeof js === 'string' ? js : undefined
-);
+/** Primitive JSON string or throws JsonError. */
+export const jString: Decoder<string> = (js: json) => {
+    if (typeof js === 'string') {
+      return js;
+    }
+    else {
+      throw new JsonError("string", js); 
+    }
+  };
+  
 
 /** JSON constant.
-    Capture the tag or returns `undefined`.
+    Capture the tag or throw JsonError.
     Can be used with [[jUnion]], although [[jEnum]]
     might be more efficient.
 */
-export function jTag<A>(tg: A): Loose<A> {
-  return (js: json) => (Object.is(js, tg) ? tg : undefined);
+export function jTag<A>(tg: A): Decoder<A> {
+  return (js: json) => {
+    if (Object.is(js, tg)) {
+      return tg;
+    }
+    else {
+      throw new JsonError(`"${tg}"`, js); 
+    }
+   };
 }
 
 /**
-   Lookup tags in a dictionary.
+   Lookup tags in a dictionary, throw JsonError if the tag is not found. 
    Can be used directly for enum types, eg. `jEnum(myEnumType)`.
  */
-export function jEnum<A>(d: { [tag: string]: A }): Loose<A> {
-  return (v: json) => (typeof v === 'string' ? d[v] : undefined);
+export function jEnum<A>(d: { [tag: string]: A }): Decoder<A> {
+  return (js: json) => {
+    if (typeof js === 'string' && js in d) {
+      return d[js];
+    }
+    else {
+      const tags = Object.keys(d).map((tg) => `"${tg}"`);
+      throw new JsonError(tags.join(' | '), js);
+    }
+  };
 }
 
 /**
-   One of the enumerated _constants_ or `undefined`.
+   One of the enumerated _constants_ or throws JsonError.
    The typechecker will prevent you from listing values that are not in
    type `A`. However, it will not protected you from missings constants in `A`.
 */
-export function jTags<A>(...values: ((string | number) & A)[]): Loose<A> {
-  const m = new Map<string | number, A>();
-  values.forEach((v) => m.set(v, v));
-  return (v: json) => (typeof v === 'string' ? m.get(v) : undefined);
-}
-
-/**
-   Refine a loose decoder with some default value.
-   The default value is returned when the provided JSON is `undefined` or
-   when the loose decoder returns `undefined`.
- */
-export function jDefault<A>(
-  fn: Loose<A>,
-  defaultValue: A,
-): Safe<A> {
-  return (js: json) => (
-    js === undefined ? defaultValue : (fn(js) ?? defaultValue)
-  );
+export function jTags<A extends string | number>(...values: A[]): Decoder<A> {
+  const m = new Set<string | number>();
+  values.forEach((v) => m.add(v));
+  return (js: json) => {
+    if ((typeof js === 'string' || typeof js === 'number') && m.has(js)) {
+      return js as A; // m.has(js) implies js extends A
+    }
+    else {
+      const tags = values.map((tg) => typeof tg === 'string' ? `"${tg}"` : tg);
+      throw new JsonError(tags.join(' | '), js);
+    }
+  };
 }
 
 /**
-   Force returning `undefined` or a default value for
-   `undefined` _or_ `null` JSON input.
-   Typically useful to leverage an existing `Safe<A>` decoder.
+   Force returning `undefined` or a default value for `undefined` _or_ `null`
+   JSON input.
  */
-export function jOption<A>(fn: Safe<A>, defaultValue?: A): Loose<A> {
+export function jOption<A>(fn: Decoder<A>, defaultValue?: A)
+    : Decoder<A | undefined> {
   return (js: json) => (
     js === undefined || js === null ? defaultValue : fn(js)
   );
 }
 
 /**
-   Fail when the loose decoder returns `undefined`.
-   See also [[jCatch]] and [[jTry]].
+   Provide a fallback value in case of a JsonError.
  */
-export function jFail<A>(fn: Loose<A>, error: string | Error): Safe<A> {
-  return (js: json) => {
-    const d = fn(js);
-    if (d !== undefined) return d;
-    throw (typeof (error) === 'string' ? new Error(error) : error);
-  };
-}
-
-/**
-   Provide a fallback value in case of undefined value or error.
-   See also [[jFail]] and [[jTry]].
- */
-export function jCatch<A>(fn: Loose<A>, fallBack: A): Safe<A> {
+export function jCatch<A>(fn: Decoder<A>, fallBack: A): Decoder<A> {
   return (js: json) => {
     try {
-      return fn(js) ?? fallBack;
-    } catch (err) {
-      D.warn(err);
-      return fallBack;
+      return fn(js);
     }
-  };
-}
-
-/**
-   Provides an (optional) default value in case of error or undefined value.
-   See also [[jFail]] and [[jCatch]].
- */
-export function jTry<A>(fn: Loose<A>, defaultValue?: A): Loose<A> {
-  return (js: json) => {
-    try {
-      return fn(js) ?? defaultValue;
-    } catch (err) {
-      D.warn(err);
-      return defaultValue;
+    catch (err) {
+      if (err instanceof JsonError) {
+        return fallBack;
+      }
+      else {
+        throw err;
+      }
     }
   };
 }
 
 /**
-   Converts maps to dictionaries.
+   Converts objects to Maps.
  */
-export function jMap<A>(fn: Loose<A>): Safe<Map<string, A>> {
+export function jMap<A>(fn: Decoder<A>): Decoder<Map<string, A>> {
   return (js: json) => {
-    const m = new Map<string, A>();
     if (js !== null && typeof js === 'object' && !Array.isArray(js)) {
-      const keys = Object.keys(js);
-      keys.forEach((k) => {
-        const v = fn(js[k]);
-        if (v !== undefined) m.set(k, v);
-      });
+      const m = new Map<string, A>();
+      for (const k of Object.keys(js)) {
+        m.set(k, fn(js[k]));
+      }
+      return m;
+    }
+    else {
+      throw new JsonError('object', js);
     }
-    return m;
   };
 }
 
@@ -282,28 +315,46 @@ export function eMap<A>(fn: Encoder<A>): Encoder<Map<string, undefined | A>> {
 }
 
 /**
-   Apply the decoder on each item of a JSON array, or return `[]` otherwise.
-   Can be also applied on a _loose_ decoder, but you will get
-   an array with possibly `undefined` elements. Use [[jList]]
-   to discard undefined elements, or use a true _safe_ decoder.
+   Apply the decoder on each item of a JSON array or throw JsonError if
+   the decoded json is not an array.
  */
-export function jArray<A>(fn: Safe<A>): Safe<A[]> {
-  return (js: json) => (Array.isArray(js) ? js.map(fn) : []);
+export function jArray<A>(fn: Decoder<A>): Decoder<A[]> {
+  return (js: json) => {
+    if (Array.isArray(js)) {
+      return js.map(fn);
+    }
+    else {
+      throw new JsonError('array', js);
+    }
+  };
 }
 
 /**
-   Apply the loose decoder on each item of a JSON array, discarding
-   all `undefined` elements. To keep the all possibly undefined array entries,
-   use [[jArray]] instead.
- */
-export function jList<A>(fn: Loose<A>): Safe<A[]> {
+    Apply the decoder on each item of a JSON array, discarding
+    all errors.
+  */
+export function jList<A>(fn: Decoder<A>): Decoder<A[]> {
   return (js: json) => {
-    const buffer: A[] = [];
-    if (Array.isArray(js)) js.forEach((vj) => {
-      const d = fn(vj);
-      if (d !== undefined) buffer.push(d);
-    });
-    return buffer;
+    if (Array.isArray(js)) {
+      const buffer = [];
+      for (const element of js) {
+        try {
+          buffer.push(fn(element));
+        }
+        catch (err) {
+          if (err instanceof JsonError) {
+            continue;
+          }
+          else {
+            throw err;
+          }
+        }  
+      }
+      return buffer;
+    }
+    else {
+      throw new JsonError('array', js);
+    }
   };
 }
 
@@ -323,105 +374,120 @@ export function eList<A>(fn: Encoder<A>): Encoder<(A | undefined)[]> {
   };
 }
 
-/** Apply a pair of decoders to JSON pairs, or return `undefined`. */
+/** Apply a pair of decoders to JSON pairs, or throw JsonError if not a pair. */
 export function jPair<A, B>(
-  fa: Safe<A>,
-  fb: Safe<B>,
-): Loose<[A, B]> {
-  return (js: json) => (Array.isArray(js) ? [
-    fa(js[0]),
-    fb(js[1]),
-  ] : undefined);
+  fa: Decoder<A>,
+  fb: Decoder<B>,
+): Decoder<[A, B]> {
+  return (js: json) => {
+    if (Array.isArray(js) && js.length === 2) {
+      return [fa(js[0]) as A, fb(js[1]) as B];
+    }
+    else {
+      throw new JsonError('[A, B]', js);
+    }
+  };
 }
 
 /** Similar to [[jPair]]. */
 export function jTriple<A, B, C>(
-  fa: Safe<A>,
-  fb: Safe<B>,
-  fc: Safe<C>,
-): Loose<[A, B, C]> {
-  return (js: json) => (Array.isArray(js) ? [
-    fa(js[0]),
-    fb(js[1]),
-    fc(js[2]),
-  ] : undefined);
+  fa: Decoder<A>,
+  fb: Decoder<B>,
+  fc: Decoder<C>,
+): Decoder<[A, B, C]> {
+  return (js: json) => {
+    if (Array.isArray(js) && js.length === 3) {
+      return [fa(js[0]), fb(js[1]), fc(js[2])];
+    }
+    else {
+      throw new JsonError('[A, B, C]', js);
+    }
+  };
 }
 
 /** Similar to [[jPair]]. */
 export function jTuple4<A, B, C, D>(
-  fa: Safe<A>,
-  fb: Safe<B>,
-  fc: Safe<C>,
-  fd: Safe<D>,
-): Loose<[A, B, C, D]> {
-  return (js: json) => (Array.isArray(js) ? [
-    fa(js[0]),
-    fb(js[1]),
-    fc(js[2]),
-    fd(js[3]),
-  ] : undefined);
+  fa: Decoder<A>,
+  fb: Decoder<B>,
+  fc: Decoder<C>,
+  fd: Decoder<D>,
+): Decoder<[A, B, C, D]> {
+  return (js: json) => {
+    if (Array.isArray(js) && js.length === 4) {
+      return [fa(js[0]), fb(js[1]), fc(js[2]), fd(js[3])];
+    }
+    else {
+      throw new JsonError('[A, B, C, D]', js);
+    }
+  };
 }
 
 /** Similar to [[jPair]]. */
 export function jTuple5<A, B, C, D, E>(
-  fa: Safe<A>,
-  fb: Safe<B>,
-  fc: Safe<C>,
-  fd: Safe<D>,
-  fe: Safe<E>,
-): Loose<[A, B, C, D, E]> {
-  return (js: json) => (Array.isArray(js) ? [
-    fa(js[0]),
-    fb(js[1]),
-    fc(js[2]),
-    fd(js[3]),
-    fe(js[4]),
-  ] : undefined);
+  fa: Decoder<A>,
+  fb: Decoder<B>,
+  fc: Decoder<C>,
+  fd: Decoder<D>,
+  fe: Decoder<E>,
+): Decoder<[A, B, C, D, E]> {
+  return (js: json) => {
+    if (Array.isArray(js) && js.length === 5) {
+      return [fa(js[0]), fb(js[1]), fc(js[2]), fd(js[3]), fe(js[4])];
+    }
+    else {
+      throw new JsonError('[A, B, C, D, E]', js);
+    }
+  };
 }
 
 /**
    Decoders for each property of object type `A`.
-   Optional fields in `A` can be assigned a loose decoder.
+   Optional fields in `A` can use jOption
 */
 export type Props<A> = {
-  [P in keyof A]: Safe<A[P]>;
+  [P in (keyof A & string)] : Decoder<A[P]>;
 };
 
 /**
    Decode an object given the decoders of its fields.
    Returns `undefined` for non-object JSON.
  */
-export function jObject<A>(fp: Props<A>): Loose<A> {
+export function jObject<A extends object>(decoders: Props<A>): Decoder<A> {
   return (js: json) => {
     if (js !== null && typeof js === 'object' && !Array.isArray(js)) {
-      const buffer = {} as A;
-      const keys = Object.keys(fp);
-      keys.forEach((k) => {
-        const fn = fp[k as keyof A];
-        if (fn !== undefined) {
-          const fj = js[k];
-          if (fj !== undefined) {
-            const fv = fn(fj);
-            if (fv !== undefined) buffer[k as keyof A] = fv;
-          }
-        }
-      });
-      return buffer;
+      const buffer : Partial<A> = {};
+      for (const k of Object.keys(decoders) as (keyof A & string)[]) {
+        buffer[k] = decoders[k](js[k]);
+      }
+      return buffer as A; // All fields should be present
+    }
+    else {
+      throw new JsonError('object', js);
     }
-    return undefined;
   };
 }
 
 /**
-   Returns the first decoder result that is not undefined.
+   Returns the first decoder result that does not fail with a JsonError.
  */
-export function jUnion<A>(...cases: Loose<A>[]): Loose<A> {
+export function jUnion<A>(...cases: Decoder<A>[]): Decoder<A> {
   return (js: json) => {
-    for (let i = 0; i < cases.length; i++) {
-      const fv = cases[i](js);
-      if (fv !== undefined) return fv;
+    const errors = [];
+    for (const fv of cases) {
+      try {
+        return fv(js);
+      }
+      catch (err) {
+        if (err instanceof JsonError) {
+          errors.push(err.expected);
+          continue;
+        }
+        else {
+          throw err;
+        }
+      }
     }
-    return undefined;
+    throw new JsonError(errors.join(' or '), js);
   };
 }
 
@@ -463,7 +529,7 @@ declare const tag: unique symbol;
 export type phantom<K, A> = A & { tag: K };
 
 export function forge<K, A>(_tag: K, data: A): phantom<K, A> {
-  return data as any;
+  return data as phantom<K, A>;
 }
 
 /** String key with kind.
@@ -475,13 +541,27 @@ export type key<K> = phantom<K, string>;
 export type index<K> = phantom<K, number>;
 
 /** Decoder for `key<K>` strings. */
-export function jKey<K>(kd: K): Loose<key<K>> {
-  return (js: json) => (typeof js === 'string' ? forge(kd, js) : undefined);
+export function jKey<K>(kd: K): Decoder<key<K>> {
+  return (js: json)  => {
+    if (typeof js === 'string') {
+      return forge(kd, js);
+    }
+    else {
+      throw new JsonError(`key<${kd}>`, js); 
+    }
+  };
 }
 
 /** Decoder for `index<K>` numbers. */
-export function jIndex<K>(kd: K): Loose<index<K>> {
-  return (js: json) => (typeof js === 'number' ? forge(kd, js) : undefined);
+export function jIndex<K>(kd: K): Decoder<index<K>> {
+  return (js: json)  => {
+    if (typeof js === 'number') {
+      return forge(kd, js);
+    }
+    else {
+      throw new JsonError(`index<${kd}>`, js); 
+    }
+  };
 }
 
 /** Dictionaries. */
@@ -491,23 +571,32 @@ export type dict<A> = { [key: string]: A };
    Decode a JSON dictionary, discarding all inconsistent entries.
    If the JSON contains no valid entry, still returns `{}`.
 */
-export function jDict<A>(fn: Loose<A>): Safe<dict<A>> {
+export function jDict<A>(fn: Decoder<A>): Decoder<dict<A>> {
   return (js: json) => {
     const buffer: dict<A> = {};
     if (js !== null && typeof js === 'object' && !Array.isArray(js)) {
-      const keys = Object.keys(js);
-      keys.forEach((key) => {
-        const fd = js[key];
-        if (fd !== undefined) {
-          const fv = fn(fd);
-          if (fv !== undefined) buffer[key] = fv;
+      for (const k of Object.keys(js)) {
+        try {
+          const fv = fn(js[k]);
+          if (fv !== undefined) {
+            buffer[k] = fv;
+          }
+        }
+        catch (err) {
+          if (err instanceof JsonError) {
+            continue;
+          }
+          else {
+            throw err;
+          }
         }
-      });
+      }
     }
     return buffer;
   };
 }
 
+
 /**
    Encode a dictionary into JSON, discarding all inconsistent entries.
    If the dictionary contains no valid entry, still returns `{}`.
diff --git a/ivette/src/dome/renderer/data/settings.ts b/ivette/src/dome/renderer/data/settings.ts
index 7678c516a52..1da27fc8c05 100644
--- a/ivette/src/dome/renderer/data/settings.ts
+++ b/ivette/src/dome/renderer/data/settings.ts
@@ -44,7 +44,7 @@ import type { State } from './states';
 
 /** @internal */
 interface Settings<A> {
-  decoder: JSON.Loose<A>;
+  decoder: JSON.Decoder<A>;
   encoder: JSON.Encoder<A>;
   defaultValue: A;
 }
@@ -62,12 +62,12 @@ interface Settings<A> {
  */
 export class GlobalSettings<A> {
   name: string;
-  decoder: JSON.Loose<A>;
+  decoder: JSON.Decoder<A>;
   encoder: JSON.Encoder<A>;
   defaultValue: A;
   constructor(
     name: string,
-    decoder: JSON.Loose<A>,
+    decoder: JSON.Decoder<A>,
     encoder: JSON.Encoder<A>,
     defaultValue: A,
   ) {
@@ -114,22 +114,22 @@ export class GString extends GlobalSettings<string> {
 export class GOption<A extends JSON.json>
   extends GlobalSettings<A | undefined>
 {
-  constructor(name: string, encoder: JSON.Loose<A>, defaultValue?: A) {
+  constructor(name: string, encoder: JSON.Decoder<A>, defaultValue?: A) {
     super(name, encoder, JSON.identity, defaultValue);
   }
 }
 
 /** Smart constructor for (JSON serializable) data with default. */
 export class GDefault<A extends JSON.json> extends GlobalSettings<A> {
-  constructor(name: string, encoder: JSON.Loose<A>, defaultValue: A) {
+  constructor(name: string, encoder: JSON.Decoder<A>, defaultValue: A) {
     super(name, encoder, JSON.identity, defaultValue);
   }
 }
 
 /** Smart constructor for object (JSON serializable) data. */
-export class GObject<A extends JSON.json> extends GlobalSettings<A> {
+export class GObject<A extends JSON.json & object> extends GlobalSettings<A> {
   constructor(name: string, fields: JSON.Props<A>, defaultValue: A) {
-    super(name, JSON.jObject(fields), JSON.identity, defaultValue);
+    super(name, JSON.jObject<A>(fields), JSON.identity, defaultValue);
   }
 }
 
@@ -248,7 +248,7 @@ function useSettings<A>(
 ): State<A> {
   // Local State
   const [value, setValue] = React.useState<A>(() => (
-    JSON.jCatch(S.decoder, S.defaultValue)(D.load(K))
+    JSON.jCatch(S.decoder, S.defaultValue)(D.load(K)) ?? S.defaultValue
   ));
   // Foreign Settings Update
   React.useEffect(() => {
@@ -288,7 +288,7 @@ const WindowSettingsDriver = new Driver({
  */
 export function getWindowSettings<A>(
   key: string | undefined,
-  decoder: JSON.Loose<A>,
+  decoder: JSON.Decoder<A>,
   defaultValue: A,
 ): A {
   return key ?
@@ -316,7 +316,7 @@ export function setWindowSettings(
  */
 export function useWindowSettings<A>(
   key: string | undefined,
-  decoder: JSON.Loose<A & JSON.json>,
+  decoder: JSON.Decoder<A & JSON.json>,
   defaultValue: A & JSON.json,
 ): State<A & JSON.json> {
   return useSettings({
@@ -329,7 +329,7 @@ export function useWindowSettings<A>(
 /** Same as [[useWindowSettings]] with a specific encoder. */
 export function useWindowSettingsData<A>(
   key: string | undefined,
-  decoder: JSON.Loose<A>,
+  decoder: JSON.Decoder<A>,
   encoder: JSON.Encoder<A>,
   defaultValue: A,
 ): State<A> {
@@ -377,7 +377,7 @@ const LocalStorageDriver = new Driver({
  */
 export function getLocalStorage<A>(
   key: string | undefined,
-  decoder: JSON.Loose<A>,
+  decoder: JSON.Decoder<A>,
   defaultValue: A,
 ): A {
   return key ?
@@ -400,7 +400,7 @@ export function setLocalStorage(
 
 export function useLocalStorage<A>(
   key: string | undefined,
-  decoder: JSON.Loose<A & JSON.json>,
+  decoder: JSON.Decoder<A & JSON.json>,
   defaultValue: A & JSON.json,
 ): State<A & JSON.json> {
   return useSettings<A & JSON.json>({
@@ -413,7 +413,7 @@ export function useLocalStorage<A>(
 /** Same as [[useLocalStorage]] with a specific encoder. */
 export function useLocalStorageData<A>(
   key: string | undefined,
-  decoder: JSON.Loose<A>,
+  decoder: JSON.Decoder<A>,
   encoder: JSON.Encoder<A>,
   defaultValue: A,
 ): State<A> {
diff --git a/ivette/src/dome/renderer/dome.tsx b/ivette/src/dome/renderer/dome.tsx
index 98369b95976..ef88eecd134 100644
--- a/ivette/src/dome/renderer/dome.tsx
+++ b/ivette/src/dome/renderer/dome.tsx
@@ -804,7 +804,7 @@ export const { useWindowSettings } = Settings;
  */
 export function useGlobalSettings<A extends Json.json>(
   globalKey: string,
-  decoder: Json.Loose<A>,
+  decoder: Json.Decoder<A>,
   defaultValue: A,
 ): State<A> {
   // Object creation is cheaper than useMemo...
diff --git a/ivette/src/dome/renderer/table/views.tsx b/ivette/src/dome/renderer/table/views.tsx
index 9277450ebf6..a4bfc26d338 100644
--- a/ivette/src/dome/renderer/table/views.tsx
+++ b/ivette/src/dome/renderer/table/views.tsx
@@ -298,7 +298,7 @@ type TableSettings = {
   visible?: Json.dict<boolean>;
 };
 
-const jTableSettings = Json.jObject({
+const jTableSettings = Json.jObject<TableSettings>({
   resize: Json.jDict(Json.jNumber),
   visible: Json.jDict(Json.jBoolean),
 });
@@ -450,7 +450,7 @@ class TableState<Key, Row> {
       const { visible } = this;
       resize.clear();
       visible.clear();
-      const theSettings: undefined | TableSettings =
+      const theSettings =
         Settings.getWindowSettings(settings, jTableSettings, undefined);
       if (theSettings) {
         forEach(theSettings.resize, (cw, cid) => {
diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx
index 6b1dd2729ad..17cad6c4aff 100644
--- a/ivette/src/frama-c/kernel/ASTview.tsx
+++ b/ivette/src/frama-c/kernel/ASTview.tsx
@@ -29,6 +29,7 @@ import _ from 'lodash';
 import CodeMirror from 'codemirror/lib/codemirror';
 
 import * as Dome from 'dome';
+import * as Json from 'dome/data/json';
 import * as Settings from 'dome/data/settings';
 import { TitleBar } from 'ivette';
 import { IconButton } from 'dome/controls/buttons';
@@ -241,7 +242,7 @@ export default function ASTview(): JSX.Element {
   }, [buffer, theMarker]);
 
   function onHover(markerId?: string): void {
-    const marker = Ast.jMarker(markerId);
+    const marker = Json.jOption(Ast.jMarker)(markerId);
     const fct = selection?.current?.fct;
     States.setHovered(marker ? { fct, marker } : undefined);
   }
diff --git a/ivette/src/frama-c/kernel/api/ast/index.ts b/ivette/src/frama-c/kernel/api/ast/index.ts
index fe8ebaddbc4..c44b83fac40 100644
--- a/ivette/src/frama-c/kernel/api/ast/index.ts
+++ b/ivette/src/frama-c/kernel/api/ast/index.ts
@@ -44,12 +44,8 @@ import { byText } from 'frama-c/kernel/api/data';
 //@ts-ignore
 import { jTag } from 'frama-c/kernel/api/data';
 //@ts-ignore
-import { jTagSafe } from 'frama-c/kernel/api/data';
-//@ts-ignore
 import { jText } from 'frama-c/kernel/api/data';
 //@ts-ignore
-import { jTextSafe } from 'frama-c/kernel/api/data';
-//@ts-ignore
 import { tag } from 'frama-c/kernel/api/data';
 //@ts-ignore
 import { text } from 'frama-c/kernel/api/data';
@@ -73,19 +69,15 @@ export const changed: Server.Signal = {
 export type source =
   { dir: string, base: string, file: string, line: number };
 
-/** Loose decoder for `source` */
-export const jSource: Json.Loose<source> =
+/** Decoder for `source` */
+export const jSource: Json.Decoder<source> =
   Json.jObject({
-    dir: Json.jFail(Json.jString,'String expected'),
-    base: Json.jFail(Json.jString,'String expected'),
-    file: Json.jFail(Json.jString,'String expected'),
-    line: Json.jFail(Json.jNumber,'Number expected'),
+    dir: Json.jString,
+    base: Json.jString,
+    file: Json.jString,
+    line: Json.jNumber,
   });
 
-/** Safe decoder for `source` */
-export const jSourceSafe: Json.Safe<source> =
-  Json.jFail(jSource,'Source expected');
-
 /** Natural order for `source` */
 export const bySource: Compare.Order<source> =
   Compare.byFields
@@ -114,12 +106,8 @@ export enum markerKind {
   property = 'property',
 }
 
-/** Loose decoder for `markerKind` */
-export const jMarkerKind: Json.Loose<markerKind> = Json.jEnum(markerKind);
-
-/** Safe decoder for `markerKind` */
-export const jMarkerKindSafe: Json.Safe<markerKind> =
-  Json.jFail(Json.jEnum(markerKind),'kernel.ast.markerKind expected');
+/** Decoder for `markerKind` */
+export const jMarkerKind: Json.Decoder<markerKind> = Json.jEnum(markerKind);
 
 /** Natural order for `markerKind` */
 export const byMarkerKind: Compare.Order<markerKind> =
@@ -129,7 +117,7 @@ const markerKindTags_internal: Server.GetRequest<null,tag[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.ast.markerKindTags',
   input:  Json.jNull,
-  output: Json.jList(jTag),
+  output: Json.jArray(jTag),
   signals: [],
 };
 /** Registered tags for the above type. */
@@ -145,12 +133,8 @@ export enum markerVar {
   function = 'function',
 }
 
-/** Loose decoder for `markerVar` */
-export const jMarkerVar: Json.Loose<markerVar> = Json.jEnum(markerVar);
-
-/** Safe decoder for `markerVar` */
-export const jMarkerVarSafe: Json.Safe<markerVar> =
-  Json.jFail(Json.jEnum(markerVar),'kernel.ast.markerVar expected');
+/** Decoder for `markerVar` */
+export const jMarkerVar: Json.Decoder<markerVar> = Json.jEnum(markerVar);
 
 /** Natural order for `markerVar` */
 export const byMarkerVar: Compare.Order<markerVar> =
@@ -160,7 +144,7 @@ const markerVarTags_internal: Server.GetRequest<null,tag[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.ast.markerVarTags',
   input:  Json.jNull,
-  output: Json.jList(jTag),
+  output: Json.jArray(jTag),
   signals: [],
 };
 /** Registered tags for the above type. */
@@ -182,21 +166,17 @@ export interface markerInfoData {
   sloc: source;
 }
 
-/** Loose decoder for `markerInfoData` */
-export const jMarkerInfoData: Json.Loose<markerInfoData> =
+/** Decoder for `markerInfoData` */
+export const jMarkerInfoData: Json.Decoder<markerInfoData> =
   Json.jObject({
-    key: Json.jFail(Json.jString,'String expected'),
-    kind: jMarkerKindSafe,
-    var: jMarkerVarSafe,
-    name: Json.jFail(Json.jString,'String expected'),
-    descr: Json.jFail(Json.jString,'String expected'),
-    sloc: jSourceSafe,
+    key: Json.jString,
+    kind: jMarkerKind,
+    var: jMarkerVar,
+    name: Json.jString,
+    descr: Json.jString,
+    sloc: jSource,
   });
 
-/** Safe decoder for `markerInfoData` */
-export const jMarkerInfoDataSafe: Json.Safe<markerInfoData> =
-  Json.jFail(jMarkerInfoData,'MarkerInfoData expected');
-
 /** Natural order for `markerInfoData` */
 export const byMarkerInfoData: Compare.Order<markerInfoData> =
   Compare.byFields
@@ -234,10 +214,10 @@ const fetchMarkerInfo_internal: Server.GetRequest<
   name:   'kernel.ast.fetchMarkerInfo',
   input:  Json.jNumber,
   output: Json.jObject({
-            pending: Json.jFail(Json.jNumber,'Number expected'),
-            updated: Json.jList(jMarkerInfoData),
-            removed: Json.jList(Json.jString),
-            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+            pending: Json.jNumber,
+            updated: Json.jArray(jMarkerInfoData),
+            removed: Json.jArray(Json.jString),
+            reload: Json.jBoolean,
           }),
   signals: [],
 };
@@ -265,8 +245,8 @@ export type marker =
   Json.key<'#expr'> | Json.key<'#term'> | Json.key<'#global'> |
   Json.key<'#property'>;
 
-/** Loose decoder for `marker` */
-export const jMarker: Json.Loose<marker> =
+/** Decoder for `marker` */
+export const jMarker: Json.Decoder<marker> =
   Json.jUnion<Json.key<'#stmt'> | Json.key<'#decl'> | Json.key<'#lval'> |
               Json.key<'#expr'> | Json.key<'#term'> | Json.key<'#global'> |
               Json.key<'#property'>>(
@@ -279,10 +259,6 @@ export const jMarker: Json.Loose<marker> =
     Json.jKey<'#property'>('#property'),
   );
 
-/** Safe decoder for `marker` */
-export const jMarkerSafe: Json.Safe<marker> =
-  Json.jFail(jMarker,'Marker expected');
-
 /** Natural order for `marker` */
 export const byMarker: Compare.Order<marker> = Compare.structural;
 
@@ -294,16 +270,9 @@ export interface location {
   marker: marker;
 }
 
-/** Loose decoder for `location` */
-export const jLocation: Json.Loose<location> =
-  Json.jObject({
-    fct: Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'),
-    marker: jMarkerSafe,
-  });
-
-/** Safe decoder for `location` */
-export const jLocationSafe: Json.Safe<location> =
-  Json.jFail(jLocation,'Location expected');
+/** Decoder for `location` */
+export const jLocation: Json.Decoder<location> =
+  Json.jObject({ fct: Json.jKey<'#fct'>('#fct'), marker: jMarker,});
 
 /** Natural order for `location` */
 export const byLocation: Compare.Order<location> =
@@ -321,7 +290,7 @@ const getMainFunction_internal: Server.GetRequest<
   kind: Server.RqKind.GET,
   name:   'kernel.ast.getMainFunction',
   input:  Json.jNull,
-  output: Json.jKey<'#fct'>('#fct'),
+  output: Json.jOption(Json.jKey<'#fct'>('#fct')),
   signals: [],
 };
 /** Get the current 'main' function. */
@@ -335,7 +304,7 @@ const getFunctions_internal: Server.GetRequest<null,Json.key<'#fct'>[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.ast.getFunctions',
   input:  Json.jNull,
-  output: Json.jList(Json.jKey<'#fct'>('#fct')),
+  output: Json.jArray(Json.jKey<'#fct'>('#fct')),
   signals: [],
 };
 /** Collect all functions in the AST */
@@ -371,24 +340,19 @@ export interface functionsData {
   sloc: source;
 }
 
-/** Loose decoder for `functionsData` */
-export const jFunctionsData: Json.Loose<functionsData> =
+/** Decoder for `functionsData` */
+export const jFunctionsData: Json.Decoder<functionsData> =
   Json.jObject({
-    key: Json.jFail(Json.jKey<'#functions'>('#functions'),
-           '#functions expected'),
-    name: Json.jFail(Json.jString,'String expected'),
-    signature: Json.jFail(Json.jString,'String expected'),
-    main: Json.jBoolean,
-    defined: Json.jBoolean,
-    stdlib: Json.jBoolean,
-    builtin: Json.jBoolean,
-    sloc: jSourceSafe,
+    key: Json.jKey<'#functions'>('#functions'),
+    name: Json.jString,
+    signature: Json.jString,
+    main: Json.jOption(Json.jBoolean),
+    defined: Json.jOption(Json.jBoolean),
+    stdlib: Json.jOption(Json.jBoolean),
+    builtin: Json.jOption(Json.jBoolean),
+    sloc: jSource,
   });
 
-/** Safe decoder for `functionsData` */
-export const jFunctionsDataSafe: Json.Safe<functionsData> =
-  Json.jFail(jFunctionsData,'FunctionsData expected');
-
 /** Natural order for `functionsData` */
 export const byFunctionsData: Compare.Order<functionsData> =
   Compare.byFields
@@ -429,10 +393,10 @@ const fetchFunctions_internal: Server.GetRequest<
   name:   'kernel.ast.fetchFunctions',
   input:  Json.jNumber,
   output: Json.jObject({
-            pending: Json.jFail(Json.jNumber,'Number expected'),
-            updated: Json.jList(jFunctionsData),
-            removed: Json.jList(Json.jKey<'#functions'>('#functions')),
-            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+            pending: Json.jNumber,
+            updated: Json.jArray(jFunctionsData),
+            removed: Json.jArray(Json.jKey<'#functions'>('#functions')),
+            reload: Json.jBoolean,
           }),
   signals: [],
 };
@@ -466,14 +430,14 @@ const getInformation_internal: Server.GetRequest<
   > = {
   kind: Server.RqKind.GET,
   name:   'kernel.ast.getInformation',
-  input:  jMarker,
-  output: Json.jList(
+  input:  Json.jOption(jMarker),
+  output: Json.jArray(
             Json.jObject({
-              id: Json.jFail(Json.jString,'String expected'),
-              label: Json.jFail(Json.jString,'String expected'),
-              descr: Json.jFail(Json.jString,'String expected'),
-              title: Json.jFail(Json.jString,'String expected'),
-              text: jTextSafe,
+              id: Json.jString,
+              label: Json.jString,
+              descr: Json.jString,
+              title: Json.jString,
+              text: jText,
             })),
   signals: [ { name: 'kernel.ast.getInformationUpdate' } ],
 };
@@ -490,13 +454,11 @@ const getMarkerAt_internal: Server.GetRequest<
   > = {
   kind: Server.RqKind.GET,
   name:   'kernel.ast.getMarkerAt',
-  input:  Json.jTry(
-            Json.jTriple(
-              Json.jFail(Json.jString,'String expected'),
-              Json.jFail(Json.jNumber,'Number expected'),
-              Json.jFail(Json.jNumber,'Number expected'),
-            )),
-  output: Json.jTry(Json.jPair( Json.jKey<'#fct'>('#fct'), jMarker,)),
+  input:  Json.jTriple( Json.jString, Json.jNumber, Json.jNumber,),
+  output: Json.jPair(
+            Json.jOption(Json.jKey<'#fct'>('#fct')),
+            Json.jOption(jMarker),
+          ),
   signals: [],
 };
 /** Returns the marker and function at a source file position, if any. Input: file path, line and column. */
@@ -509,7 +471,7 @@ const getFiles_internal: Server.GetRequest<null,string[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.ast.getFiles',
   input:  Json.jNull,
-  output: Json.jList(Json.jString),
+  output: Json.jArray(Json.jString),
   signals: [],
 };
 /** Get the currently analyzed source file names */
@@ -518,7 +480,7 @@ export const getFiles: Server.GetRequest<null,string[]>= getFiles_internal;
 const setFiles_internal: Server.SetRequest<string[],null> = {
   kind: Server.RqKind.SET,
   name:   'kernel.ast.setFiles',
-  input:  Json.jList(Json.jString),
+  input:  Json.jArray(Json.jString),
   output: Json.jNull,
   signals: [],
 };
@@ -533,16 +495,9 @@ export interface markerFromTermInput {
   term: string;
 }
 
-/** Loose decoder for `markerFromTermInput` */
-export const jMarkerFromTermInput: Json.Loose<markerFromTermInput> =
-  Json.jObject({
-    atStmt: jMarkerSafe,
-    term: Json.jFail(Json.jString,'String expected'),
-  });
-
-/** Safe decoder for `markerFromTermInput` */
-export const jMarkerFromTermInputSafe: Json.Safe<markerFromTermInput> =
-  Json.jFail(jMarkerFromTermInput,'MarkerFromTermInput expected');
+/** Decoder for `markerFromTermInput` */
+export const jMarkerFromTermInput: Json.Decoder<markerFromTermInput> =
+  Json.jObject({ atStmt: jMarker, term: Json.jString,});
 
 /** Natural order for `markerFromTermInput` */
 export const byMarkerFromTermInput: Compare.Order<markerFromTermInput> =
@@ -560,7 +515,7 @@ const markerFromTerm_internal: Server.GetRequest<
   kind: Server.RqKind.GET,
   name:   'kernel.ast.markerFromTerm',
   input:  jMarkerFromTermInput,
-  output: jMarker,
+  output: Json.jOption(jMarker),
   signals: [],
 };
 /** Build a marker from an ACSL term. */
diff --git a/ivette/src/frama-c/kernel/api/data/index.ts b/ivette/src/frama-c/kernel/api/data/index.ts
index 0ffe39eb16c..b16fbfb9b84 100644
--- a/ivette/src/frama-c/kernel/api/data/index.ts
+++ b/ivette/src/frama-c/kernel/api/data/index.ts
@@ -41,12 +41,8 @@ import * as State from 'frama-c/states';
 /** Markdown (inlined) text. */
 export type markdown = string;
 
-/** Loose decoder for `markdown` */
-export const jMarkdown: Json.Loose<markdown> = Json.jString;
-
-/** Safe decoder for `markdown` */
-export const jMarkdownSafe: Json.Safe<markdown> =
-  Json.jFail(Json.jString,'String expected');
+/** Decoder for `markdown` */
+export const jMarkdown: Json.Decoder<markdown> = Json.jString;
 
 /** Natural order for `markdown` */
 export const byMarkdown: Compare.Order<markdown> = Compare.string;
@@ -54,18 +50,14 @@ export const byMarkdown: Compare.Order<markdown> = Compare.string;
 /** Rich text format uses `[tag; …text ]` to apply the tag `tag` to the enclosed text. Empty tag `""` can also used to simply group text together. */
 export type text = null | string | text[];
 
-/** Loose decoder for `text` */
-export const jText: Json.Loose<text> =
+/** Decoder for `text` */
+export const jText: Json.Decoder<text> =
   (_x: any) => Json.jUnion<null | string | text[]>(
                  Json.jNull,
                  Json.jString,
-                 Json.jList(jText),
+                 Json.jArray(jText),
                )(_x);
 
-/** Safe decoder for `text` */
-export const jTextSafe: Json.Safe<text> =
-  (_x: any) => Json.jFail(jText,'Text expected')(_x);
-
 /** Natural order for `text` */
 export const byText: Compare.Order<text> =
   (_x: any, _y: any) => Compare.structural(_x,_y);
@@ -73,16 +65,9 @@ export const byText: Compare.Order<text> =
 /** Enum Tag Description */
 export type tag = { name: string, label: markdown, descr: markdown };
 
-/** Loose decoder for `tag` */
-export const jTag: Json.Loose<tag> =
-  Json.jObject({
-    name: Json.jFail(Json.jString,'String expected'),
-    label: jMarkdownSafe,
-    descr: jMarkdownSafe,
-  });
-
-/** Safe decoder for `tag` */
-export const jTagSafe: Json.Safe<tag> = Json.jFail(jTag,'Tag expected');
+/** Decoder for `tag` */
+export const jTag: Json.Decoder<tag> =
+  Json.jObject({ name: Json.jString, label: jMarkdown, descr: jMarkdown,});
 
 /** Natural order for `tag` */
 export const byTag: Compare.Order<tag> =
diff --git a/ivette/src/frama-c/kernel/api/project/index.ts b/ivette/src/frama-c/kernel/api/project/index.ts
index 1c99f90e498..9a103ff07d9 100644
--- a/ivette/src/frama-c/kernel/api/project/index.ts
+++ b/ivette/src/frama-c/kernel/api/project/index.ts
@@ -42,18 +42,14 @@ import * as State from 'frama-c/states';
 export type projectInfo =
   { id: Json.key<'#project'>, name: string, current: boolean };
 
-/** Loose decoder for `projectInfo` */
-export const jProjectInfo: Json.Loose<projectInfo> =
+/** Decoder for `projectInfo` */
+export const jProjectInfo: Json.Decoder<projectInfo> =
   Json.jObject({
-    id: Json.jFail(Json.jKey<'#project'>('#project'),'#project expected'),
-    name: Json.jFail(Json.jString,'String expected'),
-    current: Json.jFail(Json.jBoolean,'Boolean expected'),
+    id: Json.jKey<'#project'>('#project'),
+    name: Json.jString,
+    current: Json.jBoolean,
   });
 
-/** Safe decoder for `projectInfo` */
-export const jProjectInfoSafe: Json.Safe<projectInfo> =
-  Json.jFail(jProjectInfo,'ProjectInfo expected');
-
 /** Natural order for `projectInfo` */
 export const byProjectInfo: Compare.Order<projectInfo> =
   Compare.byFields
@@ -67,19 +63,14 @@ export const byProjectInfo: Compare.Order<projectInfo> =
 export type projectRequest =
   { project: Json.key<'#project'>, request: string, data: Json.json };
 
-/** Loose decoder for `projectRequest` */
-export const jProjectRequest: Json.Loose<projectRequest> =
+/** Decoder for `projectRequest` */
+export const jProjectRequest: Json.Decoder<projectRequest> =
   Json.jObject({
-    project: Json.jFail(Json.jKey<'#project'>('#project'),
-               '#project expected'),
-    request: Json.jFail(Json.jString,'String expected'),
+    project: Json.jKey<'#project'>('#project'),
+    request: Json.jString,
     data: Json.jAny,
   });
 
-/** Safe decoder for `projectRequest` */
-export const jProjectRequestSafe: Json.Safe<projectRequest> =
-  Json.jFail(jProjectRequest,'ProjectRequest expected');
-
 /** Natural order for `projectRequest` */
 export const byProjectRequest: Compare.Order<projectRequest> =
   Compare.byFields
@@ -113,7 +104,7 @@ const getList_internal: Server.GetRequest<null,projectInfo[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.project.getList',
   input:  Json.jNull,
-  output: Json.jList(jProjectInfo),
+  output: Json.jArray(jProjectInfo),
   signals: [],
 };
 /** Returns the list of all projects */
diff --git a/ivette/src/frama-c/kernel/api/properties/index.ts b/ivette/src/frama-c/kernel/api/properties/index.ts
index 86be4026c89..eab7ae40697 100644
--- a/ivette/src/frama-c/kernel/api/properties/index.ts
+++ b/ivette/src/frama-c/kernel/api/properties/index.ts
@@ -42,16 +42,12 @@ import { bySource } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { jSource } from 'frama-c/kernel/api/ast';
 //@ts-ignore
-import { jSourceSafe } from 'frama-c/kernel/api/ast';
-//@ts-ignore
 import { source } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { byTag } from 'frama-c/kernel/api/data';
 //@ts-ignore
 import { jTag } from 'frama-c/kernel/api/data';
 //@ts-ignore
-import { jTagSafe } from 'frama-c/kernel/api/data';
-//@ts-ignore
 import { tag } from 'frama-c/kernel/api/data';
 
 /** Property Kinds */
@@ -126,12 +122,8 @@ export enum propKind {
   extension = 'extension',
 }
 
-/** Loose decoder for `propKind` */
-export const jPropKind: Json.Loose<propKind> = Json.jEnum(propKind);
-
-/** Safe decoder for `propKind` */
-export const jPropKindSafe: Json.Safe<propKind> =
-  Json.jFail(Json.jEnum(propKind),'kernel.properties.propKind expected');
+/** Decoder for `propKind` */
+export const jPropKind: Json.Decoder<propKind> = Json.jEnum(propKind);
 
 /** Natural order for `propKind` */
 export const byPropKind: Compare.Order<propKind> = Compare.byEnum(propKind);
@@ -140,7 +132,7 @@ const propKindTags_internal: Server.GetRequest<null,tag[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.properties.propKindTags',
   input:  Json.jNull,
-  output: Json.jList(jTag),
+  output: Json.jArray(jTag),
   signals: [],
 };
 /** Registered tags for the above type. */
@@ -172,12 +164,8 @@ export enum propStatus {
   unknown_but_dead = 'unknown_but_dead',
 }
 
-/** Loose decoder for `propStatus` */
-export const jPropStatus: Json.Loose<propStatus> = Json.jEnum(propStatus);
-
-/** Safe decoder for `propStatus` */
-export const jPropStatusSafe: Json.Safe<propStatus> =
-  Json.jFail(Json.jEnum(propStatus),'kernel.properties.propStatus expected');
+/** Decoder for `propStatus` */
+export const jPropStatus: Json.Decoder<propStatus> = Json.jEnum(propStatus);
 
 /** Natural order for `propStatus` */
 export const byPropStatus: Compare.Order<propStatus> =
@@ -187,7 +175,7 @@ const propStatusTags_internal: Server.GetRequest<null,tag[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.properties.propStatusTags',
   input:  Json.jNull,
-  output: Json.jList(jTag),
+  output: Json.jArray(jTag),
   signals: [],
 };
 /** Registered tags for the above type. */
@@ -233,12 +221,8 @@ export enum alarms {
   bool_value = 'bool_value',
 }
 
-/** Loose decoder for `alarms` */
-export const jAlarms: Json.Loose<alarms> = Json.jEnum(alarms);
-
-/** Safe decoder for `alarms` */
-export const jAlarmsSafe: Json.Safe<alarms> =
-  Json.jFail(Json.jEnum(alarms),'kernel.properties.alarms expected');
+/** Decoder for `alarms` */
+export const jAlarms: Json.Decoder<alarms> = Json.jEnum(alarms);
 
 /** Natural order for `alarms` */
 export const byAlarms: Compare.Order<alarms> = Compare.byEnum(alarms);
@@ -247,7 +231,7 @@ const alarmsTags_internal: Server.GetRequest<null,tag[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.properties.alarmsTags',
   input:  Json.jNull,
-  output: Json.jList(jTag),
+  output: Json.jArray(jTag),
   signals: [],
 };
 /** Registered tags for the above type. */
@@ -279,26 +263,22 @@ export interface statusData {
   predicate?: string;
 }
 
-/** Loose decoder for `statusData` */
-export const jStatusData: Json.Loose<statusData> =
+/** Decoder for `statusData` */
+export const jStatusData: Json.Decoder<statusData> =
   Json.jObject({
-    key: Json.jFail(Json.jKey<'#property'>('#property'),'#property expected'),
-    descr: Json.jFail(Json.jString,'String expected'),
-    kind: jPropKindSafe,
-    names: Json.jList(Json.jString),
-    status: jPropStatusSafe,
-    fct: Json.jKey<'#fct'>('#fct'),
-    kinstr: Json.jKey<'#stmt'>('#stmt'),
-    source: jSourceSafe,
-    alarm: Json.jString,
-    alarm_descr: Json.jString,
-    predicate: Json.jString,
+    key: Json.jKey<'#property'>('#property'),
+    descr: Json.jString,
+    kind: jPropKind,
+    names: Json.jArray(Json.jString),
+    status: jPropStatus,
+    fct: Json.jOption(Json.jKey<'#fct'>('#fct')),
+    kinstr: Json.jOption(Json.jKey<'#stmt'>('#stmt')),
+    source: jSource,
+    alarm: Json.jOption(Json.jString),
+    alarm_descr: Json.jOption(Json.jString),
+    predicate: Json.jOption(Json.jString),
   });
 
-/** Safe decoder for `statusData` */
-export const jStatusDataSafe: Json.Safe<statusData> =
-  Json.jFail(jStatusData,'StatusData expected');
-
 /** Natural order for `statusData` */
 export const byStatusData: Compare.Order<statusData> =
   Compare.byFields
@@ -343,10 +323,10 @@ const fetchStatus_internal: Server.GetRequest<
   name:   'kernel.properties.fetchStatus',
   input:  Json.jNumber,
   output: Json.jObject({
-            pending: Json.jFail(Json.jNumber,'Number expected'),
-            updated: Json.jList(jStatusData),
-            removed: Json.jList(Json.jKey<'#property'>('#property')),
-            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+            pending: Json.jNumber,
+            updated: Json.jArray(jStatusData),
+            removed: Json.jArray(Json.jKey<'#property'>('#property')),
+            reload: Json.jBoolean,
           }),
   signals: [],
 };
diff --git a/ivette/src/frama-c/kernel/api/services/index.ts b/ivette/src/frama-c/kernel/api/services/index.ts
index 56868eadf19..0319f3998c4 100644
--- a/ivette/src/frama-c/kernel/api/services/index.ts
+++ b/ivette/src/frama-c/kernel/api/services/index.ts
@@ -44,12 +44,8 @@ import { bySource } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { jMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
-import { jMarkerSafe } from 'frama-c/kernel/api/ast';
-//@ts-ignore
 import { jSource } from 'frama-c/kernel/api/ast';
 //@ts-ignore
-import { jSourceSafe } from 'frama-c/kernel/api/ast';
-//@ts-ignore
 import { marker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { source } from 'frama-c/kernel/api/ast';
@@ -58,8 +54,6 @@ import { byTag } from 'frama-c/kernel/api/data';
 //@ts-ignore
 import { jTag } from 'frama-c/kernel/api/data';
 //@ts-ignore
-import { jTagSafe } from 'frama-c/kernel/api/data';
-//@ts-ignore
 import { tag } from 'frama-c/kernel/api/data';
 
 const getConfig_internal: Server.GetRequest<
@@ -70,9 +64,9 @@ const getConfig_internal: Server.GetRequest<
   name:   'kernel.services.getConfig',
   input:  Json.jNull,
   output: Json.jObject({
-            pluginpath: Json.jList(Json.jString),
-            datadir: Json.jList(Json.jString),
-            version: Json.jFail(Json.jString,'String expected'),
+            pluginpath: Json.jArray(Json.jString),
+            datadir: Json.jArray(Json.jString),
+            version: Json.jString,
           }),
   signals: [],
 };
@@ -86,7 +80,7 @@ const load_internal: Server.SetRequest<string,string | undefined> = {
   kind: Server.RqKind.SET,
   name:   'kernel.services.load',
   input:  Json.jString,
-  output: Json.jString,
+  output: Json.jOption(Json.jString),
   signals: [],
 };
 /** Load a save file. Returns an error, if not successfull. */
@@ -96,7 +90,7 @@ const save_internal: Server.SetRequest<string,string | undefined> = {
   kind: Server.RqKind.SET,
   name:   'kernel.services.save',
   input:  Json.jString,
-  output: Json.jString,
+  output: Json.jOption(Json.jString),
   signals: [],
 };
 /** Save the current session. Returns an error, if not successfull. */
@@ -118,12 +112,8 @@ export enum logkind {
   DEBUG = 'DEBUG',
 }
 
-/** Loose decoder for `logkind` */
-export const jLogkind: Json.Loose<logkind> = Json.jEnum(logkind);
-
-/** Safe decoder for `logkind` */
-export const jLogkindSafe: Json.Safe<logkind> =
-  Json.jFail(Json.jEnum(logkind),'kernel.services.logkind expected');
+/** Decoder for `logkind` */
+export const jLogkind: Json.Decoder<logkind> = Json.jEnum(logkind);
 
 /** Natural order for `logkind` */
 export const byLogkind: Compare.Order<logkind> = Compare.byEnum(logkind);
@@ -132,7 +122,7 @@ const logkindTags_internal: Server.GetRequest<null,tag[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.services.logkindTags',
   input:  Json.jNull,
-  output: Json.jList(jTag),
+  output: Json.jArray(jTag),
   signals: [],
 };
 /** Registered tags for the above type. */
@@ -158,23 +148,19 @@ export interface messageData {
   fct?: Json.key<'#fct'>;
 }
 
-/** Loose decoder for `messageData` */
-export const jMessageData: Json.Loose<messageData> =
+/** Decoder for `messageData` */
+export const jMessageData: Json.Decoder<messageData> =
   Json.jObject({
-    key: Json.jFail(Json.jKey<'#message'>('#message'),'#message expected'),
-    kind: jLogkindSafe,
-    plugin: Json.jFail(Json.jString,'String expected'),
-    message: Json.jFail(Json.jString,'String expected'),
-    category: Json.jString,
-    source: jSource,
-    marker: jMarker,
-    fct: Json.jKey<'#fct'>('#fct'),
+    key: Json.jKey<'#message'>('#message'),
+    kind: jLogkind,
+    plugin: Json.jString,
+    message: Json.jString,
+    category: Json.jOption(Json.jString),
+    source: Json.jOption(jSource),
+    marker: Json.jOption(jMarker),
+    fct: Json.jOption(Json.jKey<'#fct'>('#fct')),
   });
 
-/** Safe decoder for `messageData` */
-export const jMessageDataSafe: Json.Safe<messageData> =
-  Json.jFail(jMessageData,'MessageData expected');
-
 /** Natural order for `messageData` */
 export const byMessageData: Compare.Order<messageData> =
   Compare.byFields
@@ -215,10 +201,10 @@ const fetchMessage_internal: Server.GetRequest<
   name:   'kernel.services.fetchMessage',
   input:  Json.jNumber,
   output: Json.jObject({
-            pending: Json.jFail(Json.jNumber,'Number expected'),
-            updated: Json.jList(jMessageData),
-            removed: Json.jList(Json.jKey<'#message'>('#message')),
-            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+            pending: Json.jNumber,
+            updated: Json.jArray(jMessageData),
+            removed: Json.jArray(Json.jKey<'#message'>('#message')),
+            reload: Json.jBoolean,
           }),
   signals: [],
 };
@@ -254,19 +240,16 @@ export interface log {
   source?: source;
 }
 
-/** Loose decoder for `log` */
-export const jLog: Json.Loose<log> =
+/** Decoder for `log` */
+export const jLog: Json.Decoder<log> =
   Json.jObject({
-    kind: jLogkindSafe,
-    plugin: Json.jFail(Json.jString,'String expected'),
-    message: Json.jFail(Json.jString,'String expected'),
-    category: Json.jString,
-    source: jSource,
+    kind: jLogkind,
+    plugin: Json.jString,
+    message: Json.jString,
+    category: Json.jOption(Json.jString),
+    source: Json.jOption(jSource),
   });
 
-/** Safe decoder for `log` */
-export const jLogSafe: Json.Safe<log> = Json.jFail(jLog,'Log expected');
-
 /** Natural order for `log` */
 export const byLog: Compare.Order<log> =
   Compare.byFields
@@ -293,7 +276,7 @@ const getLogs_internal: Server.GetRequest<null,log[]> = {
   kind: Server.RqKind.GET,
   name:   'kernel.services.getLogs',
   input:  Json.jNull,
-  output: Json.jList(jLog),
+  output: Json.jArray(jLog),
   signals: [],
 };
 /** Flush the last emitted logs since last call (max 100) */
diff --git a/ivette/src/frama-c/plugins/dive/api/index.ts b/ivette/src/frama-c/plugins/dive/api/index.ts
index 78a1092d8ff..d3232121887 100644
--- a/ivette/src/frama-c/plugins/dive/api/index.ts
+++ b/ivette/src/frama-c/plugins/dive/api/index.ts
@@ -44,12 +44,8 @@ import { byMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { jLocation } from 'frama-c/kernel/api/ast';
 //@ts-ignore
-import { jLocationSafe } from 'frama-c/kernel/api/ast';
-//@ts-ignore
 import { jMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
-import { jMarkerSafe } from 'frama-c/kernel/api/ast';
-//@ts-ignore
 import { location } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { marker } from 'frama-c/kernel/api/ast';
@@ -62,13 +58,12 @@ export interface range {
   forward?: number;
 }
 
-/** Loose decoder for `range` */
-export const jRange: Json.Loose<range> =
-  Json.jObject({ backward: Json.jNumber, forward: Json.jNumber,});
-
-/** Safe decoder for `range` */
-export const jRangeSafe: Json.Safe<range> =
-  Json.jFail(jRange,'Range expected');
+/** Decoder for `range` */
+export const jRange: Json.Decoder<range> =
+  Json.jObject({
+    backward: Json.jOption(Json.jNumber),
+    forward: Json.jOption(Json.jNumber),
+  });
 
 /** Natural order for `range` */
 export const byRange: Compare.Order<range> =
@@ -86,13 +81,9 @@ export interface explorationWindow {
   horizon: range;
 }
 
-/** Loose decoder for `explorationWindow` */
-export const jExplorationWindow: Json.Loose<explorationWindow> =
-  Json.jObject({ perception: jRangeSafe, horizon: jRangeSafe,});
-
-/** Safe decoder for `explorationWindow` */
-export const jExplorationWindowSafe: Json.Safe<explorationWindow> =
-  Json.jFail(jExplorationWindow,'ExplorationWindow expected');
+/** Decoder for `explorationWindow` */
+export const jExplorationWindow: Json.Decoder<explorationWindow> =
+  Json.jObject({ perception: jRange, horizon: jRange,});
 
 /** Natural order for `explorationWindow` */
 export const byExplorationWindow: Compare.Order<explorationWindow> =
@@ -105,12 +96,8 @@ export const byExplorationWindow: Compare.Order<explorationWindow> =
 /** A node identifier in the graph */
 export type nodeId = number;
 
-/** Loose decoder for `nodeId` */
-export const jNodeId: Json.Loose<nodeId> = Json.jNumber;
-
-/** Safe decoder for `nodeId` */
-export const jNodeIdSafe: Json.Safe<nodeId> =
-  Json.jFail(Json.jNumber,'Number expected');
+/** Decoder for `nodeId` */
+export const jNodeId: Json.Decoder<nodeId> = Json.jNumber;
 
 /** Natural order for `nodeId` */
 export const byNodeId: Compare.Order<nodeId> = Compare.number;
@@ -118,19 +105,13 @@ export const byNodeId: Compare.Order<nodeId> = Compare.number;
 /** A callsite */
 export type callsite = { fun: string, instr: number | string };
 
-/** Loose decoder for `callsite` */
-export const jCallsite: Json.Loose<callsite> =
+/** Decoder for `callsite` */
+export const jCallsite: Json.Decoder<callsite> =
   Json.jObject({
-    fun: Json.jFail(Json.jString,'String expected'),
-    instr: Json.jFail(
-             Json.jUnion<number | string>( Json.jNumber, Json.jString,),
-             'Union expected'),
+    fun: Json.jString,
+    instr: Json.jUnion<number | string>( Json.jNumber, Json.jString,),
   });
 
-/** Safe decoder for `callsite` */
-export const jCallsiteSafe: Json.Safe<callsite> =
-  Json.jFail(jCallsite,'Callsite expected');
-
 /** Natural order for `callsite` */
 export const byCallsite: Compare.Order<callsite> =
   Compare.byFields
@@ -142,12 +123,8 @@ export const byCallsite: Compare.Order<callsite> =
 /** The callstack context for a node */
 export type callstack = callsite[];
 
-/** Safe decoder for `callstack` */
-export const jCallstackSafe: Json.Safe<callstack> =
-  Json.jArray(jCallsiteSafe);
-
-/** Loose decoder for `callstack` */
-export const jCallstack: Json.Loose<callstack> = Json.jTry(jCallstackSafe);
+/** Decoder for `callstack` */
+export const jCallstack: Json.Decoder<callstack> = Json.jArray(jCallsite);
 
 /** Natural order for `callstack` */
 export const byCallstack: Compare.Order<callstack> =
@@ -156,16 +133,9 @@ export const byCallstack: Compare.Order<callstack> =
 /** The description of a node locality */
 export type nodeLocality = { file: string, callstack?: callstack };
 
-/** Loose decoder for `nodeLocality` */
-export const jNodeLocality: Json.Loose<nodeLocality> =
-  Json.jObject({
-    file: Json.jFail(Json.jString,'String expected'),
-    callstack: jCallstack,
-  });
-
-/** Safe decoder for `nodeLocality` */
-export const jNodeLocalitySafe: Json.Safe<nodeLocality> =
-  Json.jFail(jNodeLocality,'NodeLocality expected');
+/** Decoder for `nodeLocality` */
+export const jNodeLocality: Json.Decoder<nodeLocality> =
+  Json.jObject({ file: Json.jString, callstack: Json.jOption(jCallstack),});
 
 /** Natural order for `nodeLocality` */
 export const byNodeLocality: Compare.Order<nodeLocality> =
@@ -182,27 +152,22 @@ export type node =
     writes: location[], values?: string, range: number | string,
     type?: string };
 
-/** Loose decoder for `node` */
-export const jNode: Json.Loose<node> =
+/** Decoder for `node` */
+export const jNode: Json.Decoder<node> =
   Json.jObject({
-    id: jNodeIdSafe,
-    label: Json.jFail(Json.jString,'String expected'),
-    kind: Json.jFail(Json.jString,'String expected'),
-    locality: jNodeLocalitySafe,
-    is_root: Json.jFail(Json.jBoolean,'Boolean expected'),
-    backward_explored: Json.jFail(Json.jString,'String expected'),
-    forward_explored: Json.jFail(Json.jString,'String expected'),
-    writes: Json.jArray(jLocationSafe),
-    values: Json.jString,
-    range: Json.jFail(
-             Json.jUnion<number | string>( Json.jNumber, Json.jString,),
-             'Union expected'),
-    type: Json.jString,
+    id: jNodeId,
+    label: Json.jString,
+    kind: Json.jString,
+    locality: jNodeLocality,
+    is_root: Json.jBoolean,
+    backward_explored: Json.jString,
+    forward_explored: Json.jString,
+    writes: Json.jArray(jLocation),
+    values: Json.jOption(Json.jString),
+    range: Json.jUnion<number | string>( Json.jNumber, Json.jString,),
+    type: Json.jOption(Json.jString),
   });
 
-/** Safe decoder for `node` */
-export const jNodeSafe: Json.Safe<node> = Json.jFail(jNode,'Node expected');
-
 /** Natural order for `node` */
 export const byNode: Compare.Order<node> =
   Compare.byFields
@@ -227,20 +192,16 @@ export const byNode: Compare.Order<node> =
 export type dependency =
   { id: number, src: nodeId, dst: nodeId, kind: string, origins: location[] };
 
-/** Loose decoder for `dependency` */
-export const jDependency: Json.Loose<dependency> =
+/** Decoder for `dependency` */
+export const jDependency: Json.Decoder<dependency> =
   Json.jObject({
-    id: Json.jFail(Json.jNumber,'Number expected'),
-    src: jNodeIdSafe,
-    dst: jNodeIdSafe,
-    kind: Json.jFail(Json.jString,'String expected'),
-    origins: Json.jArray(jLocationSafe),
+    id: Json.jNumber,
+    src: jNodeId,
+    dst: jNodeId,
+    kind: Json.jString,
+    origins: Json.jArray(jLocation),
   });
 
-/** Safe decoder for `dependency` */
-export const jDependencySafe: Json.Safe<dependency> =
-  Json.jFail(jDependency,'Dependency expected');
-
 /** Natural order for `dependency` */
 export const byDependency: Compare.Order<dependency> =
   Compare.byFields
@@ -256,16 +217,9 @@ export const byDependency: Compare.Order<dependency> =
 /** The whole graph being built */
 export type graphData = { nodes: node[], deps: dependency[] };
 
-/** Loose decoder for `graphData` */
-export const jGraphData: Json.Loose<graphData> =
-  Json.jObject({
-    nodes: Json.jArray(jNodeSafe),
-    deps: Json.jArray(jDependencySafe),
-  });
-
-/** Safe decoder for `graphData` */
-export const jGraphDataSafe: Json.Safe<graphData> =
-  Json.jFail(jGraphData,'GraphData expected');
+/** Decoder for `graphData` */
+export const jGraphData: Json.Decoder<graphData> =
+  Json.jObject({ nodes: Json.jArray(jNode), deps: Json.jArray(jDependency),});
 
 /** Natural order for `graphData` */
 export const byGraphData: Compare.Order<graphData> =
@@ -280,22 +234,17 @@ export type diffData =
   { root?: nodeId, add: { nodes: node[], deps: dependency[] }, sub: nodeId[]
     };
 
-/** Loose decoder for `diffData` */
-export const jDiffData: Json.Loose<diffData> =
+/** Decoder for `diffData` */
+export const jDiffData: Json.Decoder<diffData> =
   Json.jObject({
-    root: jNodeId,
-    add: Json.jFail(
-           Json.jObject({
-             nodes: Json.jArray(jNodeSafe),
-             deps: Json.jArray(jDependencySafe),
-           }),'Record expected'),
-    sub: Json.jArray(jNodeIdSafe),
+    root: Json.jOption(jNodeId),
+    add: Json.jObject({
+           nodes: Json.jArray(jNode),
+           deps: Json.jArray(jDependency),
+         }),
+    sub: Json.jArray(jNodeId),
   });
 
-/** Safe decoder for `diffData` */
-export const jDiffDataSafe: Json.Safe<diffData> =
-  Json.jFail(jDiffData,'DiffData expected');
-
 /** Natural order for `diffData` */
 export const byDiffData: Compare.Order<diffData> =
   Compare.byFields
diff --git a/ivette/src/frama-c/plugins/eva/api/general/index.ts b/ivette/src/frama-c/plugins/eva/api/general/index.ts
index cf5797288c8..08a43ba5347 100644
--- a/ivette/src/frama-c/plugins/eva/api/general/index.ts
+++ b/ivette/src/frama-c/plugins/eva/api/general/index.ts
@@ -42,33 +42,25 @@ import { byMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { jMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
-import { jMarkerSafe } from 'frama-c/kernel/api/ast';
-//@ts-ignore
 import { marker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { byTag } from 'frama-c/kernel/api/data';
 //@ts-ignore
 import { jTag } from 'frama-c/kernel/api/data';
 //@ts-ignore
-import { jTagSafe } from 'frama-c/kernel/api/data';
-//@ts-ignore
 import { tag } from 'frama-c/kernel/api/data';
 
 /** State of the computation of Eva Analysis. */
 export type computationStateType = "not_computed" | "computing" | "computed";
 
-/** Loose decoder for `computationStateType` */
-export const jComputationStateType: Json.Loose<computationStateType> =
+/** Decoder for `computationStateType` */
+export const jComputationStateType: Json.Decoder<computationStateType> =
   Json.jUnion<"not_computed" | "computing" | "computed">(
     Json.jTag("not_computed"),
     Json.jTag("computing"),
     Json.jTag("computed"),
   );
 
-/** Safe decoder for `computationStateType` */
-export const jComputationStateTypeSafe: Json.Safe<computationStateType> =
-  Json.jFail(jComputationStateType,'ComputationStateType expected');
-
 /** Natural order for `computationStateType` */
 export const byComputationStateType: Compare.Order<computationStateType> =
   Compare.structural;
@@ -109,12 +101,11 @@ const getCallers_internal: Server.GetRequest<
   kind: Server.RqKind.GET,
   name:   'plugins.eva.general.getCallers',
   input:  Json.jKey<'#fct'>('#fct'),
-  output: Json.jList(
-            Json.jTry(
-              Json.jPair(
-                Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'),
-                Json.jFail(Json.jKey<'#stmt'>('#stmt'),'#stmt expected'),
-              ))),
+  output: Json.jArray(
+            Json.jPair(
+              Json.jKey<'#fct'>('#fct'),
+              Json.jKey<'#stmt'>('#stmt'),
+            )),
   signals: [],
 };
 /** Get the list of call site of a function */
@@ -131,18 +122,13 @@ export interface functionsData {
   eva_analyzed?: boolean;
 }
 
-/** Loose decoder for `functionsData` */
-export const jFunctionsData: Json.Loose<functionsData> =
+/** Decoder for `functionsData` */
+export const jFunctionsData: Json.Decoder<functionsData> =
   Json.jObject({
-    key: Json.jFail(Json.jKey<'#functions'>('#functions'),
-           '#functions expected'),
-    eva_analyzed: Json.jBoolean,
+    key: Json.jKey<'#functions'>('#functions'),
+    eva_analyzed: Json.jOption(Json.jBoolean),
   });
 
-/** Safe decoder for `functionsData` */
-export const jFunctionsDataSafe: Json.Safe<functionsData> =
-  Json.jFail(jFunctionsData,'FunctionsData expected');
-
 /** Natural order for `functionsData` */
 export const byFunctionsData: Compare.Order<functionsData> =
   Compare.byFields
@@ -175,10 +161,10 @@ const fetchFunctions_internal: Server.GetRequest<
   name:   'plugins.eva.general.fetchFunctions',
   input:  Json.jNumber,
   output: Json.jObject({
-            pending: Json.jFail(Json.jNumber,'Number expected'),
-            updated: Json.jList(jFunctionsData),
-            removed: Json.jList(Json.jKey<'#functions'>('#functions')),
-            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+            pending: Json.jNumber,
+            updated: Json.jArray(jFunctionsData),
+            removed: Json.jArray(Json.jKey<'#functions'>('#functions')),
+            reload: Json.jBoolean,
           }),
   signals: [],
 };
@@ -208,17 +194,13 @@ export interface deadCode {
   nonTerminating: marker[];
 }
 
-/** Loose decoder for `deadCode` */
-export const jDeadCode: Json.Loose<deadCode> =
+/** Decoder for `deadCode` */
+export const jDeadCode: Json.Decoder<deadCode> =
   Json.jObject({
-    unreachable: Json.jList(jMarker),
-    nonTerminating: Json.jList(jMarker),
+    unreachable: Json.jArray(jMarker),
+    nonTerminating: Json.jArray(jMarker),
   });
 
-/** Safe decoder for `deadCode` */
-export const jDeadCodeSafe: Json.Safe<deadCode> =
-  Json.jFail(jDeadCode,'DeadCode expected');
-
 /** Natural order for `deadCode` */
 export const byDeadCode: Compare.Order<deadCode> =
   Compare.byFields
@@ -257,13 +239,9 @@ export enum taintStatus {
   not_tainted = 'not_tainted',
 }
 
-/** Loose decoder for `taintStatus` */
-export const jTaintStatus: Json.Loose<taintStatus> = Json.jEnum(taintStatus);
-
-/** Safe decoder for `taintStatus` */
-export const jTaintStatusSafe: Json.Safe<taintStatus> =
-  Json.jFail(Json.jEnum(taintStatus),
-    'plugins.eva.general.taintStatus expected');
+/** Decoder for `taintStatus` */
+export const jTaintStatus: Json.Decoder<taintStatus> =
+  Json.jEnum(taintStatus);
 
 /** Natural order for `taintStatus` */
 export const byTaintStatus: Compare.Order<taintStatus> =
@@ -273,7 +251,7 @@ const taintStatusTags_internal: Server.GetRequest<null,tag[]> = {
   kind: Server.RqKind.GET,
   name:   'plugins.eva.general.taintStatusTags',
   input:  Json.jNull,
-  output: Json.jList(jTag),
+  output: Json.jArray(jTag),
   signals: [],
 };
 /** Registered tags for the above type. */
@@ -289,18 +267,14 @@ export interface propertiesData {
   taint: taintStatus;
 }
 
-/** Loose decoder for `propertiesData` */
-export const jPropertiesData: Json.Loose<propertiesData> =
+/** Decoder for `propertiesData` */
+export const jPropertiesData: Json.Decoder<propertiesData> =
   Json.jObject({
-    key: Json.jFail(Json.jKey<'#property'>('#property'),'#property expected'),
-    priority: Json.jFail(Json.jBoolean,'Boolean expected'),
-    taint: jTaintStatusSafe,
+    key: Json.jKey<'#property'>('#property'),
+    priority: Json.jBoolean,
+    taint: jTaintStatus,
   });
 
-/** Safe decoder for `propertiesData` */
-export const jPropertiesDataSafe: Json.Safe<propertiesData> =
-  Json.jFail(jPropertiesData,'PropertiesData expected');
-
 /** Natural order for `propertiesData` */
 export const byPropertiesData: Compare.Order<propertiesData> =
   Compare.byFields
@@ -334,10 +308,10 @@ const fetchProperties_internal: Server.GetRequest<
   name:   'plugins.eva.general.fetchProperties',
   input:  Json.jNumber,
   output: Json.jObject({
-            pending: Json.jFail(Json.jNumber,'Number expected'),
-            updated: Json.jList(jPropertiesData),
-            removed: Json.jList(Json.jKey<'#property'>('#property')),
-            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+            pending: Json.jNumber,
+            updated: Json.jArray(jPropertiesData),
+            removed: Json.jArray(Json.jKey<'#property'>('#property')),
+            reload: Json.jBoolean,
           }),
   signals: [],
 };
@@ -383,15 +357,10 @@ export enum alarmCategory {
   other = 'other',
 }
 
-/** Loose decoder for `alarmCategory` */
-export const jAlarmCategory: Json.Loose<alarmCategory> =
+/** Decoder for `alarmCategory` */
+export const jAlarmCategory: Json.Decoder<alarmCategory> =
   Json.jEnum(alarmCategory);
 
-/** Safe decoder for `alarmCategory` */
-export const jAlarmCategorySafe: Json.Safe<alarmCategory> =
-  Json.jFail(Json.jEnum(alarmCategory),
-    'plugins.eva.general.alarmCategory expected');
-
 /** Natural order for `alarmCategory` */
 export const byAlarmCategory: Compare.Order<alarmCategory> =
   Compare.byEnum(alarmCategory);
@@ -400,7 +369,7 @@ const alarmCategoryTags_internal: Server.GetRequest<null,tag[]> = {
   kind: Server.RqKind.GET,
   name:   'plugins.eva.general.alarmCategoryTags',
   input:  Json.jNull,
-  output: Json.jList(jTag),
+  output: Json.jArray(jTag),
   signals: [],
 };
 /** Registered tags for the above type. */
@@ -410,18 +379,14 @@ export const alarmCategoryTags: Server.GetRequest<null,tag[]>= alarmCategoryTags
 export type statusesEntry =
   { valid: number, unknown: number, invalid: number };
 
-/** Loose decoder for `statusesEntry` */
-export const jStatusesEntry: Json.Loose<statusesEntry> =
+/** Decoder for `statusesEntry` */
+export const jStatusesEntry: Json.Decoder<statusesEntry> =
   Json.jObject({
-    valid: Json.jFail(Json.jNumber,'Number expected'),
-    unknown: Json.jFail(Json.jNumber,'Number expected'),
-    invalid: Json.jFail(Json.jNumber,'Number expected'),
+    valid: Json.jNumber,
+    unknown: Json.jNumber,
+    invalid: Json.jNumber,
   });
 
-/** Safe decoder for `statusesEntry` */
-export const jStatusesEntrySafe: Json.Safe<statusesEntry> =
-  Json.jFail(jStatusesEntry,'StatusesEntry expected');
-
 /** Natural order for `statusesEntry` */
 export const byStatusesEntry: Compare.Order<statusesEntry> =
   Compare.byFields
@@ -434,16 +399,9 @@ export const byStatusesEntry: Compare.Order<statusesEntry> =
 /** Alarm count for each alarm category. */
 export type alarmEntry = { category: alarmCategory, count: number };
 
-/** Loose decoder for `alarmEntry` */
-export const jAlarmEntry: Json.Loose<alarmEntry> =
-  Json.jObject({
-    category: jAlarmCategorySafe,
-    count: Json.jFail(Json.jNumber,'Number expected'),
-  });
-
-/** Safe decoder for `alarmEntry` */
-export const jAlarmEntrySafe: Json.Safe<alarmEntry> =
-  Json.jFail(jAlarmEntry,'AlarmEntry expected');
+/** Decoder for `alarmEntry` */
+export const jAlarmEntry: Json.Decoder<alarmEntry> =
+  Json.jObject({ category: jAlarmCategory, count: Json.jNumber,});
 
 /** Natural order for `alarmEntry` */
 export const byAlarmEntry: Compare.Order<alarmEntry> =
@@ -463,41 +421,28 @@ export type programStatsType =
     alarmsStatuses: statusesEntry, assertionsStatuses: statusesEntry,
     precondsStatuses: statusesEntry };
 
-/** Loose decoder for `programStatsType` */
-export const jProgramStatsType: Json.Loose<programStatsType> =
+/** Decoder for `programStatsType` */
+export const jProgramStatsType: Json.Decoder<programStatsType> =
   Json.jObject({
-    progFunCoverage: Json.jFail(
-                       Json.jObject({
-                         reachable: Json.jFail(Json.jNumber,
-                                      'Number expected'),
-                         dead: Json.jFail(Json.jNumber,'Number expected'),
-                       }),'Record expected'),
-    progStmtCoverage: Json.jFail(
-                        Json.jObject({
-                          reachable: Json.jFail(Json.jNumber,
-                                       'Number expected'),
-                          dead: Json.jFail(Json.jNumber,'Number expected'),
-                        }),'Record expected'),
-    progAlarms: Json.jList(jAlarmEntry),
-    evaEvents: Json.jFail(
-                 Json.jObject({
-                   errors: Json.jFail(Json.jNumber,'Number expected'),
-                   warnings: Json.jFail(Json.jNumber,'Number expected'),
-                 }),'Record expected'),
-    kernelEvents: Json.jFail(
-                    Json.jObject({
-                      errors: Json.jFail(Json.jNumber,'Number expected'),
-                      warnings: Json.jFail(Json.jNumber,'Number expected'),
-                    }),'Record expected'),
-    alarmsStatuses: jStatusesEntrySafe,
-    assertionsStatuses: jStatusesEntrySafe,
-    precondsStatuses: jStatusesEntrySafe,
+    progFunCoverage: Json.jObject({
+                       reachable: Json.jNumber,
+                       dead: Json.jNumber,
+                     }),
+    progStmtCoverage: Json.jObject({
+                        reachable: Json.jNumber,
+                        dead: Json.jNumber,
+                      }),
+    progAlarms: Json.jArray(jAlarmEntry),
+    evaEvents: Json.jObject({ errors: Json.jNumber, warnings: Json.jNumber,}),
+    kernelEvents: Json.jObject({
+                    errors: Json.jNumber,
+                    warnings: Json.jNumber,
+                  }),
+    alarmsStatuses: jStatusesEntry,
+    assertionsStatuses: jStatusesEntry,
+    precondsStatuses: jStatusesEntry,
   });
 
-/** Safe decoder for `programStatsType` */
-export const jProgramStatsTypeSafe: Json.Safe<programStatsType> =
-  Json.jFail(jProgramStatsType,'ProgramStatsType expected');
-
 /** Natural order for `programStatsType` */
 export const byProgramStatsType: Compare.Order<programStatsType> =
   Compare.byFields
@@ -569,23 +514,15 @@ export interface functionStatsData {
   alarmStatuses: statusesEntry;
 }
 
-/** Loose decoder for `functionStatsData` */
-export const jFunctionStatsData: Json.Loose<functionStatsData> =
+/** Decoder for `functionStatsData` */
+export const jFunctionStatsData: Json.Decoder<functionStatsData> =
   Json.jObject({
-    key: Json.jFail(Json.jKey<'#fundec'>('#fundec'),'#fundec expected'),
-    coverage: Json.jFail(
-                Json.jObject({
-                  reachable: Json.jFail(Json.jNumber,'Number expected'),
-                  dead: Json.jFail(Json.jNumber,'Number expected'),
-                }),'Record expected'),
-    alarmCount: Json.jList(jAlarmEntry),
-    alarmStatuses: jStatusesEntrySafe,
+    key: Json.jKey<'#fundec'>('#fundec'),
+    coverage: Json.jObject({ reachable: Json.jNumber, dead: Json.jNumber,}),
+    alarmCount: Json.jArray(jAlarmEntry),
+    alarmStatuses: jStatusesEntry,
   });
 
-/** Safe decoder for `functionStatsData` */
-export const jFunctionStatsDataSafe: Json.Safe<functionStatsData> =
-  Json.jFail(jFunctionStatsData,'FunctionStatsData expected');
-
 /** Natural order for `functionStatsData` */
 export const byFunctionStatsData: Compare.Order<functionStatsData> =
   Compare.byFields
@@ -626,10 +563,10 @@ const fetchFunctionStats_internal: Server.GetRequest<
   name:   'plugins.eva.general.fetchFunctionStats',
   input:  Json.jNumber,
   output: Json.jObject({
-            pending: Json.jFail(Json.jNumber,'Number expected'),
-            updated: Json.jList(jFunctionStatsData),
-            removed: Json.jList(Json.jKey<'#fundec'>('#fundec')),
-            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+            pending: Json.jNumber,
+            updated: Json.jArray(jFunctionStatsData),
+            removed: Json.jArray(Json.jKey<'#fundec'>('#fundec')),
+            reload: Json.jBoolean,
           }),
   signals: [],
 };
@@ -663,18 +600,9 @@ const getStates_internal: Server.GetRequest<
   > = {
   kind: Server.RqKind.GET,
   name:   'plugins.eva.general.getStates',
-  input:  Json.jTry(
-            Json.jPair(
-              jMarkerSafe,
-              Json.jFail(Json.jBoolean,'Boolean expected'),
-            )),
-  output: Json.jList(
-            Json.jTry(
-              Json.jTriple(
-                Json.jFail(Json.jString,'String expected'),
-                Json.jFail(Json.jString,'String expected'),
-                Json.jFail(Json.jString,'String expected'),
-              ))),
+  input:  Json.jPair( jMarker, Json.jBoolean,),
+  output: Json.jArray(
+            Json.jTriple( Json.jString, Json.jString, Json.jString,)),
   signals: [],
 };
 /** Get the domain states about the given marker */
diff --git a/ivette/src/frama-c/plugins/eva/api/values/index.ts b/ivette/src/frama-c/plugins/eva/api/values/index.ts
index c286426c70a..b713376b0b4 100644
--- a/ivette/src/frama-c/plugins/eva/api/values/index.ts
+++ b/ivette/src/frama-c/plugins/eva/api/values/index.ts
@@ -42,8 +42,6 @@ import { byMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { jMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
-import { jMarkerSafe } from 'frama-c/kernel/api/ast';
-//@ts-ignore
 import { marker } from 'frama-c/kernel/api/ast';
 
 /** Emitted when EVA results has changed */
@@ -53,23 +51,18 @@ export const changed: Server.Signal = {
 
 export type callstack = Json.index<'#eva-callstack-id'>;
 
-/** Loose decoder for `callstack` */
-export const jCallstack: Json.Loose<callstack> =
+/** Decoder for `callstack` */
+export const jCallstack: Json.Decoder<callstack> =
   Json.jIndex<'#eva-callstack-id'>('#eva-callstack-id');
 
-/** Safe decoder for `callstack` */
-export const jCallstackSafe: Json.Safe<callstack> =
-  Json.jFail(Json.jIndex<'#eva-callstack-id'>('#eva-callstack-id'),
-    '#eva-callstack-id expected');
-
 /** Natural order for `callstack` */
 export const byCallstack: Compare.Order<callstack> = Compare.number;
 
 const getCallstacks_internal: Server.GetRequest<marker[],callstack[]> = {
   kind: Server.RqKind.GET,
   name:   'plugins.eva.values.getCallstacks',
-  input:  Json.jList(jMarker),
-  output: Json.jList(jCallstack),
+  input:  Json.jArray(jMarker),
+  output: Json.jArray(jCallstack),
   signals: [],
 };
 /** Callstacks for markers */
@@ -83,12 +76,12 @@ const getCallstackInfo_internal: Server.GetRequest<
   kind: Server.RqKind.GET,
   name:   'plugins.eva.values.getCallstackInfo',
   input:  jCallstack,
-  output: Json.jList(
+  output: Json.jArray(
             Json.jObject({
-              callee: Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'),
-              caller: Json.jKey<'#fct'>('#fct'),
-              stmt: Json.jKey<'#stmt'>('#stmt'),
-              rank: Json.jNumber,
+              callee: Json.jKey<'#fct'>('#fct'),
+              caller: Json.jOption(Json.jKey<'#fct'>('#fct')),
+              stmt: Json.jOption(Json.jKey<'#stmt'>('#stmt')),
+              rank: Json.jOption(Json.jNumber),
             })),
   signals: [],
 };
@@ -106,9 +99,7 @@ const getStmtInfo_internal: Server.GetRequest<
   kind: Server.RqKind.GET,
   name:   'plugins.eva.values.getStmtInfo',
   input:  Json.jKey<'#stmt'>('#stmt'),
-  output: Json.jObject({
-            rank: Json.jFail(Json.jNumber,'Number expected'),
-            fct: Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'),
+  output: Json.jObject({ rank: Json.jNumber, fct: Json.jKey<'#fct'>('#fct'),
           }),
   signals: [],
 };
@@ -127,12 +118,12 @@ const getProbeInfo_internal: Server.GetRequest<
   name:   'plugins.eva.values.getProbeInfo',
   input:  jMarker,
   output: Json.jObject({
-            condition: Json.jFail(Json.jBoolean,'Boolean expected'),
-            effects: Json.jFail(Json.jBoolean,'Boolean expected'),
-            rank: Json.jFail(Json.jNumber,'Number expected'),
-            stmt: Json.jKey<'#stmt'>('#stmt'),
-            code: Json.jString,
-            evaluable: Json.jFail(Json.jBoolean,'Boolean expected'),
+            condition: Json.jBoolean,
+            effects: Json.jBoolean,
+            rank: Json.jNumber,
+            stmt: Json.jOption(Json.jKey<'#stmt'>('#stmt')),
+            code: Json.jOption(Json.jString),
+            evaluable: Json.jBoolean,
           }),
   signals: [],
 };
@@ -153,33 +144,22 @@ export interface evaluation {
   pointedVars: [ string, marker ][];
 }
 
-/** Loose decoder for `evaluation` */
-export const jEvaluation: Json.Loose<evaluation> =
+/** Decoder for `evaluation` */
+export const jEvaluation: Json.Decoder<evaluation> =
   Json.jObject({
-    value: Json.jFail(Json.jString,'String expected'),
-    alarms: Json.jList(
-              Json.jTry(
-                Json.jPair(
-                  Json.jFail(
-                    Json.jUnion<"True" | "False" | "Unknown">(
-                      Json.jTag("True"),
-                      Json.jTag("False"),
-                      Json.jTag("Unknown"),
-                    ),'Union expected'),
-                  Json.jFail(Json.jString,'String expected'),
-                ))),
-    pointedVars: Json.jList(
-                   Json.jTry(
-                     Json.jPair(
-                       Json.jFail(Json.jString,'String expected'),
-                       jMarkerSafe,
-                     ))),
+    value: Json.jString,
+    alarms: Json.jArray(
+              Json.jPair(
+                Json.jUnion<"True" | "False" | "Unknown">(
+                  Json.jTag("True"),
+                  Json.jTag("False"),
+                  Json.jTag("Unknown"),
+                ),
+                Json.jString,
+              )),
+    pointedVars: Json.jArray(Json.jPair( Json.jString, jMarker,)),
   });
 
-/** Safe decoder for `evaluation` */
-export const jEvaluationSafe: Json.Safe<evaluation> =
-  Json.jFail(jEvaluation,'Evaluation expected');
-
 /** Natural order for `evaluation` */
 export const byEvaluation: Compare.Order<evaluation> =
   Compare.byFields
@@ -197,12 +177,15 @@ const getValues_internal: Server.GetRequest<
   > = {
   kind: Server.RqKind.GET,
   name:   'plugins.eva.values.getValues',
-  input:  Json.jObject({ callstack: jCallstack, target: jMarkerSafe,}),
+  input:  Json.jObject({
+            callstack: Json.jOption(jCallstack),
+            target: jMarker,
+          }),
   output: Json.jObject({
-            vElse: jEvaluation,
-            vThen: jEvaluation,
-            vAfter: jEvaluation,
-            vBefore: jEvaluation,
+            vElse: Json.jOption(jEvaluation),
+            vThen: Json.jOption(jEvaluation),
+            vAfter: Json.jOption(jEvaluation),
+            vBefore: Json.jOption(jEvaluation),
           }),
   signals: [],
 };
diff --git a/ivette/src/frama-c/plugins/pivot/api/general/index.ts b/ivette/src/frama-c/plugins/pivot/api/general/index.ts
index dc968c2c385..ab2c478b87e 100644
--- a/ivette/src/frama-c/plugins/pivot/api/general/index.ts
+++ b/ivette/src/frama-c/plugins/pivot/api/general/index.ts
@@ -41,13 +41,9 @@ import * as State from 'frama-c/states';
 /** State of the pivot table source data. */
 export type tableStateType = string[][];
 
-/** Safe decoder for `tableStateType` */
-export const jTableStateTypeSafe: Json.Safe<tableStateType> =
-  Json.jArray(Json.jArray(Json.jFail(Json.jString,'String expected')));
-
-/** Loose decoder for `tableStateType` */
-export const jTableStateType: Json.Loose<tableStateType> =
-  Json.jTry(jTableStateTypeSafe);
+/** Decoder for `tableStateType` */
+export const jTableStateType: Json.Decoder<tableStateType> =
+  Json.jArray(Json.jArray(Json.jString));
 
 /** Natural order for `tableStateType` */
 export const byTableStateType: Compare.Order<tableStateType> =
diff --git a/ivette/src/frama-c/plugins/studia/api/studia/index.ts b/ivette/src/frama-c/plugins/studia/api/studia/index.ts
index f0e0e32becc..54b71933609 100644
--- a/ivette/src/frama-c/plugins/studia/api/studia/index.ts
+++ b/ivette/src/frama-c/plugins/studia/api/studia/index.ts
@@ -42,8 +42,6 @@ import { byMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
 import { jMarker } from 'frama-c/kernel/api/ast';
 //@ts-ignore
-import { jMarkerSafe } from 'frama-c/kernel/api/ast';
-//@ts-ignore
 import { marker } from 'frama-c/kernel/api/ast';
 
 /** Statements that read or write a location. */
@@ -54,27 +52,13 @@ export interface effects {
   indirect: [ Json.key<'#fct'>, marker ][];
 }
 
-/** Loose decoder for `effects` */
-export const jEffects: Json.Loose<effects> =
+/** Decoder for `effects` */
+export const jEffects: Json.Decoder<effects> =
   Json.jObject({
-    direct: Json.jList(
-              Json.jTry(
-                Json.jPair(
-                  Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'),
-                  jMarkerSafe,
-                ))),
-    indirect: Json.jList(
-                Json.jTry(
-                  Json.jPair(
-                    Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'),
-                    jMarkerSafe,
-                  ))),
+    direct: Json.jArray(Json.jPair( Json.jKey<'#fct'>('#fct'), jMarker,)),
+    indirect: Json.jArray(Json.jPair( Json.jKey<'#fct'>('#fct'), jMarker,)),
   });
 
-/** Safe decoder for `effects` */
-export const jEffectsSafe: Json.Safe<effects> =
-  Json.jFail(jEffects,'Effects expected');
-
 /** Natural order for `effects` */
 export const byEffects: Compare.Order<effects> =
   Compare.byFields
diff --git a/ivette/src/frama-c/server.ts b/ivette/src/frama-c/server.ts
index d0ade05e197..510cad2e81f 100644
--- a/ivette/src/frama-c/server.ts
+++ b/ivette/src/frama-c/server.ts
@@ -730,9 +730,9 @@ export interface Request<Kd extends RqKind, In, Out> {
   /** The request full name. */
   name: string;
   /** Encoder of input parameters. */
-  input: Json.Loose<In>;
+  input: Json.Decoder<In>;
   /** Decoder of output parameters. */
-  output: Json.Loose<Out>;
+  output: Json.Decoder<Out>;
   /** Signals the request depends on */
   signals: Array<Signal>;
 }
diff --git a/ivette/src/renderer/Laboratory.tsx b/ivette/src/renderer/Laboratory.tsx
index d530a3baf67..a944186dcd5 100644
--- a/ivette/src/renderer/Laboratory.tsx
+++ b/ivette/src/renderer/Laboratory.tsx
@@ -268,13 +268,13 @@ function CustomViews(props: CustomViewsProps): JSX.Element {
   const { settings, shape, setShape, views: libViews } = props;
   const [local, setLocal] = Settings.useWindowSettings<CustomViewsSettings>(
     settings,
-    Json.identity as Json.Loose<CustomViewsSettings & Json.json>, // Clearly abusive conversion, a real decoder is needed
+    Json.identity as Json.Decoder<CustomViewsSettings & Json.json>, // Clearly abusive conversion, a real decoder is needed
     {},
   );
   const [customs, setCustoms] =
     Settings.useLocalStorage<{ [id: string]: View }>(
       'frama-c.labview',
-      Json.identity as Json.Loose<{ [id: string]: View } & Json.json>, // Clearly abusive conversion, a real decoder is needed
+      Json.identity as Json.Decoder<{ [id: string]: View } & Json.json>, // Clearly abusive conversion, a real decoder is needed
       {},
     );
   const [edited, setEdited] = React.useState<string>();
diff --git a/src/plugins/api-generator/api_generator.ml b/src/plugins/api-generator/api_generator.ml
index 58e8852eef6..4bfa7b77d4d 100644
--- a/src/plugins/api-generator/api_generator.ml
+++ b/src/plugins/api-generator/api_generator.ml
@@ -108,7 +108,7 @@ let makeJtype ?self ~names =
       Pretty_utils.pp_list ~pre:"@[<hov 0>" ~sep:" |@ " ~suf:"@]" protect fmt js
     | Jrecord fjs ->
       Pretty_utils.pp_list ~pre:"@[<hov 2>{ " ~sep:",@ " ~suf:"@ }@]" field fmt fjs
-    | Jarray js | Jlist js -> Format.fprintf fmt "%a[]" protect js
+    | Jarray js -> Format.fprintf fmt "%a[]" protect js
   and protect fmt js = match js with
     | Junion _ | Joption _ -> Format.fprintf fmt "@[<hov 2>(%a)@]" pp js
     | _ -> pp fmt js
@@ -132,12 +132,6 @@ let jcall names fmt id =
   try Format.pp_print_string fmt (Pkg.IdMap.find id names)
   with Not_found -> Self.abort "Undefined identifier '%a'" Pkg.pp_ident id
 
-let jsafe ~safe msg pp fmt d =
-  if safe then
-    Format.fprintf fmt "@[<hov 2>Json.jFail(@,%a,@,'%s expected')@]" pp d msg
-  else
-    pp fmt d
-
 let jtry ~safe pp fmt d =
   if safe then
     pp fmt d
@@ -146,25 +140,25 @@ let jtry ~safe pp fmt d =
 
 let jenum names fmt id = Format.fprintf fmt "Json.jEnum(%a)" (jcall names) id
 
-let junion ~jtype ~makeLoose fmt jts =
+let junion ~jtype ~make fmt jts =
   begin
     Format.fprintf fmt "@[<hv 0>@[<hv 2>Json.jUnion<%a>("
       jtype (Pkg.Junion jts) ;
     List.iter
-      (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," makeLoose js) jts ;
+      (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," make js) jts ;
     Format.fprintf fmt "@]@,)@]" ;
   end
 
-let jrecord ~makeSafe fmt jts =
+let jrecord ~make fmt jts =
   begin
     Format.fprintf fmt "@[<hv 0>@[<hv 2>Json.jObject({" ;
     List.iter
       (fun (fd,js) ->
-         Format.fprintf fmt "@ @[<hov 2>%s: %a@]," fd makeSafe js) jts ;
+         Format.fprintf fmt "@ @[<hov 2>%s: %a@]," fd make js) jts ;
     Format.fprintf fmt "@]@,})@]" ;
   end
 
-let jtuple ~makeSafe fmt jts =
+let jtuple ~make fmt jts =
   begin
     let name = match List.length jts with
       | 2 -> "jPair"
@@ -175,58 +169,41 @@ let jtuple ~makeSafe fmt jts =
     in
     Format.fprintf fmt "@[<hv 0>@[<hv 2>Json.%s(" name ;
     List.iter
-      (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," makeSafe js) jts ;
+      (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," make js) jts ;
     Format.fprintf fmt "@]@,)@]" ;
   end
 
-let rec makeDecoder ~safe ?self ~names fmt js =
+let rec makeDecoder ?self ~names fmt js =
   let open Pkg in
-  let makeSafe = makeDecoder ?self ~names ~safe:true in
-  let makeLoose = makeDecoder ?self ~names ~safe:false in
+  let make = makeDecoder ?self ~names in
   match js with
   | Jany -> jprim fmt "jAny"
   | Jnull -> jprim fmt "jNull"
-  | Jboolean -> jsafe ~safe "Boolean" jprim fmt "jBoolean"
-  | Jnumber -> jsafe ~safe "Number" jprim fmt "jNumber"
-  | Jstring | Jalpha -> jsafe ~safe "String" jprim fmt "jString"
+  | Jboolean -> jprim fmt "jBoolean"
+  | Jnumber -> jprim fmt "jNumber"
+  | Jstring | Jalpha -> jprim fmt "jString"
   | Jtag a -> Format.fprintf fmt "Json.jTag(\"%s\")" a
-  | Jkey kd -> jsafe ~safe ("#" ^ kd) jkey fmt kd
-  | Jindex kd -> jsafe ~safe ("#" ^ kd) jindex fmt kd
-  | Jdata id -> jcall names fmt (Pkg.Derived.decode ~safe id)
-  | Jenum id -> jsafe ~safe (Pkg.name_of_ident id) (jenum names) fmt id
-  | Jself -> jcall names fmt (Pkg.Derived.decode ~safe (getSelf self))
-  | Joption js -> makeLoose fmt js
+  | Jkey kd -> jkey fmt kd
+  | Jindex kd -> jindex fmt kd
+  | Jdata id -> jcall names fmt (Pkg.Derived.decode id)
+  | Jenum id -> jenum names fmt id
+  | Jself -> jcall names fmt (Pkg.Derived.decode (getSelf self))
+  | Joption js ->
+    Format.fprintf fmt "@[<hov 2>Json.jOption(@,%a)@]" make js
   | Jdict js ->
-    Format.fprintf fmt "@[<hov 2>Json.jDict(@,%a)@]" makeLoose js
-  | Jlist js ->
-    Format.fprintf fmt "@[<hov 2>Json.jList(@,%a)@]" makeLoose js
+    Format.fprintf fmt "@[<hov 2>Json.jDict(@,%a)@]" make js
   | Jarray js ->
-    if safe
-    then Format.fprintf fmt "@[<hov 2>Json.jArray(%a)@]" makeSafe js
-    else Format.fprintf fmt "@[<hov 2>Json.jTry(jArray(%a))@]" makeSafe js
+    Format.fprintf fmt "@[<hov 2>Json.jArray(@,%a)@]" make js
   | Junion jts ->
     let jtype = makeJtype ?self ~names in
-    jsafe ~safe "Union" (junion ~jtype ~makeLoose) fmt jts
-  | Jrecord jfs -> jsafe ~safe "Record" (jrecord ~makeSafe) fmt jfs
-  | Jtuple jts -> jtry ~safe (jtuple ~makeSafe) fmt jts
+    junion ~jtype ~make fmt jts
+  | Jrecord jfs -> jrecord ~make fmt jfs
+  | Jtuple jts -> jtuple ~make fmt jts
 
 let makeLooseNeedSafe = function
   | Pkg.Jtuple _ | Pkg.Jarray _ -> true
   | _ -> false
 
-let makeRootDecoder ~safe ~self ~names fmt js =
-  let open Pkg in
-  match js with
-  | Joption _ | Jdict _ | Jlist _ when safe ->
-    jcall names fmt (Pkg.Derived.loose self)
-  | Jtuple _ | Jarray _ when not safe ->
-    Format.fprintf fmt "Json.jTry(%a)"
-      (jcall names) (Pkg.Derived.safe self)
-  | Junion _ | Jrecord _ when safe ->
-    Format.fprintf fmt "Json.jFail(%a,'%s expected')"
-      (jcall names) (Pkg.Derived.loose self)
-      (String.capitalize_ascii self.name)
-  | _ -> makeDecoder ~safe ~self ~names fmt js
 
 (* -------------------------------------------------------------------------- *)
 (* --- Parameter Decoder                                                  --- *)
@@ -254,7 +231,7 @@ let makeOrder ~self ~names fmt js =
       Format.fprintf fmt "@[<hov 2>Compare.defined(@,%a)@]" pp js
     | Jenum id ->
       Format.fprintf fmt "@[<hov 2>Compare.byEnum(@,%a)@]" (jcall names) id
-    | Jlist js | Jarray js ->
+    | Jarray js ->
       Format.fprintf fmt "@[<hov 2>Compare.array(@,%a)@]" pp js
     | Jtuple jts ->
       let name = match List.length jts with
@@ -341,7 +318,7 @@ let makeDeclaration fmt names d =
     let prefix = String.capitalize_ascii (String.lowercase_ascii kind) in
     let input = typeOfParam rq.rq_input in
     let output = typeOfParam rq.rq_output in
-    let makeParam fmt js = makeDecoder ~safe:false ~names fmt js in
+    let makeParam fmt js = makeDecoder ~names fmt js in
     Format.fprintf fmt
       "@[<hv 2>const %s_internal: Server.%sRequest<@,%a,@,%a@,>@] = {@\n"
       self.name prefix jtype input jtype output ;
@@ -416,19 +393,12 @@ let makeDeclaration fmt names d =
       "@[<hv 2>export const %s: State.Array<@,%a,@,%a@,>@] = %s_internal;@\n"
       self.name jtype jkey jtype jrow self.name ;
 
-  | D_safe(id,js) ->
-    makeDescr fmt d.d_descr ;
-    Format.fprintf fmt
-      "@[<hov 2>@[<hv 0>export const %s: Json.Safe<@,%a@,>@] =@ %a;@]\n"
-      self.name (jcall names) id
-      (makeRecursive (makeRootDecoder ~safe:true ~self:id ~names)) js
-
-  | D_loose(id,js) ->
+  | D_decoder(id,js) ->
     makeDescr fmt d.d_descr ;
     Format.fprintf fmt
-      "@[<hov 2>@[<hv 0>export const %s: Json.Loose<@,%a@,>@] =@ %a;@]\n"
+      "@[<hov 2>@[<hv 0>export const %s: Json.Decoder<@,%a@,>@] =@ %a;@]\n"
       self.name (jcall names) id
-      (makeRecursive (makeRootDecoder ~safe:false ~self:id ~names)) js
+      (makeRecursive (makeDecoder ~self:id ~names)) js
 
   | D_order(id,js) ->
     makeDescr fmt d.d_descr ;
@@ -449,8 +419,6 @@ type ranking = {
 
 let depends d =
   match d.Pkg.d_kind with
-  | D_loose(id,t) when makeLooseNeedSafe t -> [Pkg.Derived.safe id]
-  | D_safe(id,t) when not (makeLooseNeedSafe t) -> [Pkg.Derived.loose id]
   | D_value _ ->
     let id = d.d_ident in
     [
@@ -469,8 +437,7 @@ let depends d =
     let data = Pkg.Derived.data id in
     [
       data ;
-      Pkg.Derived.loose data ;
-      Pkg.Derived.safe data ;
+      Pkg.Derived.decode data ;
       Pkg.Derived.order data ;
       Pkg.Derived.signal id ;
       Pkg.Derived.reload id ;
diff --git a/src/plugins/eva/api/general_requests.ml b/src/plugins/eva/api/general_requests.ml
index af6c92b62ae..357298d59aa 100644
--- a/src/plugins/eva/api/general_requests.ml
+++ b/src/plugins/eva/api/general_requests.ml
@@ -509,7 +509,7 @@ end
 module Alarms =
 struct
   type t = (AlarmCategory.t * int) list
-  let jtype = Package.Jlist AlarmEntry.jtype
+  let jtype = Package.Jarray AlarmEntry.jtype
   let to_json x = `List (List.map AlarmEntry.to_json x)
 end
 
diff --git a/src/plugins/eva/api/values_request.ml b/src/plugins/eva/api/values_request.ml
index 8714daa8f22..032d9776bc8 100644
--- a/src/plugins/eva/api/values_request.ml
+++ b/src/plugins/eva/api/values_request.ml
@@ -208,7 +208,7 @@ module Jcalls : Request.Output with type t = callstack = struct
 
   type t = callstack
 
-  let jtype = Package.(Jlist (Jrecord [
+  let jtype = Package.(Jarray (Jrecord [
       "callee" , Jkf.jtype ;
       "caller" , Joption Jkf.jtype ;
       "stmt" , Joption Jstmt.jtype ;
diff --git a/src/plugins/server/data.ml b/src/plugins/server/data.ml
index 8b9722ba5d0..eda26bfe758 100644
--- a/src/plugins/server/data.ml
+++ b/src/plugins/server/data.ml
@@ -64,12 +64,9 @@ let package = Package.package ~name:"data" ~title:"Informations" ()
 let derived ~package ~id jtype =
   let module Md = Markdown in
   begin
-    declare ~package ~name:(Derived.safe id).name
-      ~descr:(Md.plain "Safe decoder for" @ Md.code id.name)
-      (D_safe(id,jtype)) ;
-    declare ~package ~name:(Derived.loose id).name
-      ~descr:(Md.plain "Loose decoder for" @ Md.code id.name)
-      (D_loose(id,jtype)) ;
+    declare ~package ~name:(Derived.decode id).name
+      ~descr:(Md.plain "Decoder for" @ Md.code id.name)
+      (D_decoder(id,jtype)) ;
     declare ~package ~name:(Derived.order id).name
       ~descr:(Md.plain "Natural order for" @ Md.code id.name)
       (D_order(id,jtype)) ;
@@ -130,14 +127,6 @@ end
 (* -------------------------------------------------------------------------- *)
 
 module Jlist(A : S) : S with type t = A.t list =
-struct
-  type t = A.t list
-  let jtype = Jlist A.jtype
-  let to_json xs = `List (List.map A.to_json xs)
-  let of_json js = List.map A.of_json (Ju.to_list js)
-end
-
-module Jalist(A : S) : S with type t = A.t list =
 struct
   type t = A.t list
   let jtype = Jarray A.jtype
@@ -239,7 +228,7 @@ struct
         "Rich text format uses `[tag; …text ]` to apply \
          the tag `tag` to the enclosed text. \
          Empty tag `\"\"` can also used to simply group text together." in
-    let jdef = Junion [ Jnull; Jstring; Jlist Jself ] in
+    let jdef = Junion [ Jnull; Jstring; Jarray Jself ] in
     declare ~package ~name:"text" ~descr jdef
 end
 
@@ -284,7 +273,7 @@ let jlist (type a) (d : a data) : a list data =
   (module A : S with type t = a list)
 
 let jalist (type a) (d : a data) : a list data =
-  let module A = Jalist(val d) in
+  let module A = Jlist(val d) in
   (module A : S with type t = a list)
 
 let jarray (type a) (d : a data) : a array data =
diff --git a/src/plugins/server/data.mli b/src/plugins/server/data.mli
index 87305705e39..cd056414d54 100644
--- a/src/plugins/server/data.mli
+++ b/src/plugins/server/data.mli
@@ -99,7 +99,6 @@ module Joption(A : S) : S with type t = A.t option
 module Jpair(A : S)(B : S) : S with type t = A.t * B.t
 module Jtriple(A : S)(B : S)(C : S) : S with type t = A.t * B.t * C.t
 module Jlist(A : S) : S with type t = A.t list
-module Jalist(A : S) : S with type t = A.t list
 module Jarray(A : S) : S with type t = A.t array
 
 (* -------------------------------------------------------------------------- *)
diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml
index 07150d8d185..feb0f41fcc8 100644
--- a/src/plugins/server/package.ml
+++ b/src/plugins/server/package.ml
@@ -171,7 +171,6 @@ type jtype =
   | Jindex of string (* kind of an integer used for indexing *)
   | Joption of jtype
   | Jdict of jtype (* dictionaries *)
-  | Jlist of jtype (* order does not matter *)
   | Jarray of jtype (* order matters *)
   | Jtuple of jtype list
   | Junion of jtype list
@@ -221,8 +220,7 @@ type declKindInfo =
   | D_value of jtype
   | D_state of jtype
   | D_array of arrayInfo (* key kind *)
-  | D_safe of ident * jtype (* safe decoder *)
-  | D_loose of ident * jtype (* loose decoder *)
+  | D_decoder of ident * jtype
   | D_order of ident * jtype (* natural ordering *)
 
 type declInfo = {
@@ -278,9 +276,7 @@ struct
   let fetch id = derived ~prefix:"fetch" id
   let reload id = derived ~prefix:"reload" id
   let order id = derived ~prefix:"by" id
-  let loose id = derived ~prefix:"j" id
-  let safe id = derived ~prefix:"j" ~suffix:"Safe" id
-  let decode ~safe:ok id = if ok then safe id else loose id
+  let decode id = derived ~prefix:"j" id
 end
 
 (* -------------------------------------------------------------------------- *)
@@ -292,21 +288,20 @@ let rec isRecursive = function
   | Jdata _ | Jenum _
   | Jany | Jnull | Jboolean | Jnumber
   | Jstring | Jalpha | Jkey _ | Jindex _ | Jtag _ -> false
-  | Joption js | Jdict js  | Jarray js | Jlist js -> isRecursive js
+  | Joption js | Jdict js  | Jarray js -> isRecursive js
   | Jtuple js | Junion js -> List.exists isRecursive js
   | Jrecord fjs -> List.exists (fun (_,js) -> isRecursive js) fjs
 
 let rec visit_jtype fn = function
   | Jany | Jself | Jnull | Jboolean | Jnumber
   | Jstring | Jalpha | Jkey _ | Jindex _ | Jtag _ -> ()
-  | Joption js | Jdict js  | Jarray js | Jlist js -> visit_jtype fn js
+  | Joption js | Jdict js  | Jarray js -> visit_jtype fn js
   | Jtuple js | Junion js -> List.iter (visit_jtype fn) js
   | Jrecord fjs -> List.iter (fun (_,js) -> visit_jtype fn js) fjs
   | Jdata id | Jenum id ->
     begin
       fn id ;
-      fn (Derived.safe id) ;
-      fn (Derived.loose id) ;
+      fn (Derived.decode id) ;
       fn (Derived.order id) ;
     end
 
@@ -322,7 +317,7 @@ let visit_request f { rq_input ; rq_output } =
 let visit_dkind f = function
   | D_signal | D_enum _ | D_array _ -> ()
   | D_type js | D_state js | D_value js -> visit_jtype f js
-  | D_loose(id,js) | D_safe(id,js) | D_order(id,js) -> f id ; visit_jtype f js
+  | D_decoder (id,js) | D_order(id,js) -> f id ; visit_jtype f js
   | D_record fds -> List.iter (visit_field f) fds
   | D_request rq -> visit_request f rq
 
@@ -470,7 +465,7 @@ let rec md_jtype pp = function
   | Joption js -> protect pp js @ Md.code "?"
   | Jtuple js -> Md.code "[" @ md_jlist pp "," js @ Md.code "]"
   | Junion js -> md_jlist pp "|" js
-  | Jarray js | Jlist js -> protect pp js @ Md.code "[]"
+  | Jarray js -> protect pp js @ Md.code "[]"
   | Jrecord fjs -> Md.code "{" @ fields pp fjs @ Md.code "}"
   | Jdict js ->
     Md.code "{[key]:" @ md_jtype pp js @ Md.code "}"
diff --git a/src/plugins/server/package.mli b/src/plugins/server/package.mli
index 56b0f3a34c0..55023a1b939 100644
--- a/src/plugins/server/package.mli
+++ b/src/plugins/server/package.mli
@@ -39,7 +39,6 @@ type jtype =
   | Jindex of string (** kind of an integer used for indexing *)
   | Joption of jtype
   | Jdict of jtype (** dictionaries *)
-  | Jlist of jtype (** order does not matter *)
   | Jarray of jtype (** order matters *)
   | Jtuple of jtype list
   | Junion of jtype list
@@ -85,8 +84,7 @@ type declKindInfo =
   | D_value of jtype
   | D_state of jtype
   | D_array of arrayInfo
-  | D_safe of ident * jtype (* safe decoder *)
-  | D_loose of ident * jtype (* loose decoder *)
+  | D_decoder of ident * jtype
   | D_order of ident * jtype (* natural ordering *)
 
 type declInfo = {
@@ -127,10 +125,8 @@ sig
   val data : ident -> ident
   val fetch : ident -> ident
   val reload : ident -> ident
-  val safe : ident -> ident
-  val loose : ident -> ident
   val order : ident -> ident
-  val decode : safe:bool -> ident -> ident
+  val decode : ident -> ident
 end
 
 (* -------------------------------------------------------------------------- *)
diff --git a/src/plugins/server/server_doc.ml b/src/plugins/server/server_doc.ml
index a1c14afd4fd..d2ba06ba700 100644
--- a/src/plugins/server/server_doc.ml
+++ b/src/plugins/server/server_doc.ml
@@ -134,7 +134,7 @@ let kind_of_decl = function
   | D_request { rq_kind=`GET } -> "GET"
   | D_request { rq_kind=`SET } -> "SET"
   | D_request { rq_kind=`EXEC } -> "EXEC"
-  | D_loose _ | D_safe _ | D_order _ -> assert false
+  | D_decoder _ | D_order _ -> assert false
 
 let pp_for ?decl names =
   let self =
@@ -165,7 +165,7 @@ let md_signals signals =
 
 let descr_of_decl names decl =
   match decl.d_kind with
-  | D_safe _ | D_loose _  | D_order _ -> assert false
+  | D_decoder _ | D_order _ -> assert false
   | D_signal -> []
   | D_state _ -> [] (* TBC *)
   | D_value _ -> [] (* TBC *)
@@ -191,7 +191,7 @@ let descr_of_decl names decl =
 
 let declaration page names decl =
   match decl.d_kind with
-  | D_safe _ | D_loose _ | D_order _ -> ()
+  | D_decoder _ | D_order _ -> ()
   | _ ->
     let name = decl.d_ident.name in
     let fullname = name_of_ident decl.d_ident in
-- 
GitLab