diff --git a/.gitmodules b/.gitmodules
index 0163ef86549d9ee0ba792961799f705881d1f893..58efd108e858ae06dde5f626286bd3d73f9dde4e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,7 +1,4 @@
 [submodule "relast-preprocessor"]
 	path = relast-preprocessor
 	url = ../relast-preprocessor.git
-  branch = jastadd-fix-inc-param-debug
-[submodule "ragconnect.base/src/main/jastadd/mustache"]
-	path = ragconnect.base/src/main/jastadd/mustache
-	url = ../mustache
+	branch = develop
diff --git a/ragconnect.base/build.gradle b/ragconnect.base/build.gradle
index e212a394a62cd29887daa30973dfc9ceb39af6be..77bafe579a620ca243e1061785fcf1ddef8a3108 100644
--- a/ragconnect.base/build.gradle
+++ b/ragconnect.base/build.gradle
@@ -78,7 +78,7 @@ jar {
 File preprocessorGrammar = file('../relast-preprocessor/src/main/jastadd/RelAst.relast')
 File ragConnectGrammar = file('./src/main/jastadd/RagConnect.relast')
 File intermediateGrammar = file('./src/main/jastadd/intermediate/MustacheNodes.relast')
-File mustacheGrammar = file('./src/main/jastadd/mustache/Mustache.relast')
+File mustacheGrammar = file('../relast-preprocessor/src/main/jastadd/mustache/Mustache.relast')
 task relast(type: JavaExec) {
     group = 'Build'
     main = "-jar"
@@ -220,3 +220,4 @@ publishing {
 }
 
 publish.dependsOn jar
+jar.dependsOn ":relast-preprocessor:jar"
diff --git a/ragconnect.base/src/main/jastadd/Navigation.jrag b/ragconnect.base/src/main/jastadd/Navigation.jrag
index 6ab782f07256aa39b97099ce6d0b982b5f02c1c8..d3890f7d22a195127e7688435f9168aa64a37eac 100644
--- a/ragconnect.base/src/main/jastadd/Navigation.jrag
+++ b/ragconnect.base/src/main/jastadd/Navigation.jrag
@@ -1,7 +1,7 @@
 import java.util.List;
 import java.util.ArrayList;
 
-aspect Navigation {
+aspect RagConnectNavigation {
 
   // --- program ---
   eq RagConnect.getChild().program() = getProgram();
@@ -12,16 +12,27 @@ aspect Navigation {
   eq RagConnect.getChild().ragconnect() = this;
   eq MRagConnect.getChild().ragconnect() = getRagConnect();
 
+  // --- containedConnectSpecification ---
+  inh ConnectSpecification ASTNode.containedConnectSpecification();
+  eq RagConnect.getChild().containedConnectSpecification() = null;
+  eq MRagConnect.getChild().containedConnectSpecification() = null;
+  eq Document.getChild().containedConnectSpecification() = null;
+  eq Program.getChild().containedConnectSpecification() = null;
+  eq ConnectSpecification.getChild().containedConnectSpecification() = this;
+
   // --- containedFile
-  eq Grammar.getChild().containedFile() = null;
   eq RagConnect.getChild().containedFile() = null;
   eq MRagConnect.getChild().containedFile() = null;
 
   // --- containedFileName ---
-  eq Grammar.getChild().containedFileName() = null;  // should be in PP
-  eq RagConnect.getChild().containedFileName() = null;
-  eq ConnectSpecificationFile.getChild().containedFileName() = getFileName();
-  eq MRagConnect.getChild().containedFileName() = null;
+  eq ConnectSpecificationFile.containedFileName() = getFileName();
+  refine Navigation eq ASTNode.containedFileName() {
+    if (containedFile() == null) {
+      return containedConnectSpecification().containedFileName();
+    }
+    return refined();
+//    return containedFile().getFileName();
+  }
 
   //--- allEndpointDefinitionList ---
   syn List<EndpointDefinition> RagConnect.allEndpointDefinitionList() {
@@ -128,8 +139,6 @@ aspect Navigation {
   // --- rootTypeComponents ---
   syn JastAddList<MTypeComponent> MHandler.rootTypeComponents() = mragconnect().getRootTypeComponents();
 
-  // === for preprocessor ===
-  // --- isOptComponent ---
-  syn boolean TypeComponent.isOptComponent() = false;
-  eq OptComponent.isOptComponent() = true;
+  // --- isListComponent --- (defined in PP, but only on TypeComponent)
+  syn boolean Component.isListComponent() = false;
 }
diff --git a/ragconnect.base/src/main/jastadd/intermediate2mustache/MustacheNodesToYAML.jrag b/ragconnect.base/src/main/jastadd/intermediate2mustache/MustacheNodesToYAML.jrag
index 9de1c1e6ecf3e2f05580b3c324316708e353ad40..ef54a74e6fd57f11f17530e53524c63446277ca3 100644
--- a/ragconnect.base/src/main/jastadd/intermediate2mustache/MustacheNodesToYAML.jrag
+++ b/ragconnect.base/src/main/jastadd/intermediate2mustache/MustacheNodesToYAML.jrag
@@ -206,5 +206,5 @@ aspect Navigation {
   eq Document.getChild().program() = null;
   eq Document.getChild().ragconnect() = null;
   eq Document.getChild().containedFile() = null;
-  eq Document.getChild().containedFileName() = getFileName();
+  eq Document.containedFileName() = getFileName();
 }
diff --git a/ragconnect.base/src/main/jastadd/mustache b/ragconnect.base/src/main/jastadd/mustache
deleted file mode 160000
index c10bed0d03e3fa18b8133ce1de48de7646899615..0000000000000000000000000000000000000000
--- a/ragconnect.base/src/main/jastadd/mustache
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit c10bed0d03e3fa18b8133ce1de48de7646899615
diff --git a/ragconnect.tests/src/test/01-input/regression-tests/issue27/.gitignore b/ragconnect.tests/src/test/01-input/regression-tests/issue27/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..607b7610731b1ddf9dc05e605bd374a4b59ea360
--- /dev/null
+++ b/ragconnect.tests/src/test/01-input/regression-tests/issue27/.gitignore
@@ -0,0 +1 @@
+/*.noNewLine.*
diff --git a/ragconnect.tests/src/test/01-input/regression-tests/issue27/README.md b/ragconnect.tests/src/test/01-input/regression-tests/issue27/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..96595af1b32ba8487f2e8e663a944b0be52dff28
--- /dev/null
+++ b/ragconnect.tests/src/test/01-input/regression-tests/issue27/README.md
@@ -0,0 +1,3 @@
+# Issue27
+
+Regression test for failing parser when missing newline at end of specification.
diff --git a/ragconnect.tests/src/test/01-input/regression-tests/issue27/Test.connect b/ragconnect.tests/src/test/01-input/regression-tests/issue27/Test.connect
new file mode 100644
index 0000000000000000000000000000000000000000..28827bb62d7b801cf2f8bc605afc90c122f0cb6a
--- /dev/null
+++ b/ragconnect.tests/src/test/01-input/regression-tests/issue27/Test.connect
@@ -0,0 +1 @@
+receive A.Name ;
diff --git a/ragconnect.tests/src/test/01-input/regression-tests/issue27/Test.relast b/ragconnect.tests/src/test/01-input/regression-tests/issue27/Test.relast
new file mode 100644
index 0000000000000000000000000000000000000000..4c479a5756a37e42c74459c22006912445baa9b3
--- /dev/null
+++ b/ragconnect.tests/src/test/01-input/regression-tests/issue27/Test.relast
@@ -0,0 +1 @@
+A ::= <Name:String> ;
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java
index 47fa7c7c60d24d934ff2a979461a041319bdb49b..4d32adff23abd12f2052f320466b79dc0f8673f5 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java
@@ -2,7 +2,6 @@ package org.jastadd.ragconnect.tests;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.jastadd.ragconnect.compiler.Compiler;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
@@ -10,14 +9,14 @@ import org.junit.jupiter.api.Test;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
-import java.util.ArrayList;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.jastadd.ragconnect.tests.TestUtils.exec;
 import static org.jastadd.ragconnect.tests.TestUtils.readFile;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -25,8 +24,8 @@ public class Errors {
 
   private static final Logger logger = LogManager.getLogger(Errors.class);
   private static final String FILENAME_PATTERN = "$FILENAME";
-  private static final String INPUT_DIRECTORY = "./src/test/01-input/errors/";
-  private static final String OUTPUT_DIRECTORY = "./src/test/02-after-ragconnect/errors/";
+  private static final String ERROR_DIRECTORY = "errors/";
+  private static final String OUTPUT_DIRECTORY = TestUtils.OUTPUT_DIRECTORY_PREFIX + ERROR_DIRECTORY;
 
   private static final String DEFAULT_GRAMMAR_NAME = "Errors";
 
@@ -48,44 +47,21 @@ public class Errors {
 
   @SuppressWarnings("SameParameterValue")
   private void test(String expectedName, String rootNode, String... connectNames) throws IOException {
-    String grammarFile = INPUT_DIRECTORY + DEFAULT_GRAMMAR_NAME + ".relast";
-//    String ragconnectFile = INPUT_DIRECTORY + name + ".connect";
-    String outFile = OUTPUT_DIRECTORY + expectedName + ".out";
-    String expectedFile = INPUT_DIRECTORY + expectedName + ".expected";
-
-    assertThat(connectNames).isNotEmpty();
-
-    try {
-      logger.debug("user.dir: {}", System.getProperty("user.dir"));
-      List<String> args = new ArrayList<>() {{
-          add("--o=" + OUTPUT_DIRECTORY);
-          add("--rootNode=" + rootNode);
-          add("--verbose");
-          add(grammarFile);
-      }};
-      for (String connectName : connectNames) {
-        args.add(INPUT_DIRECTORY + connectName + ".connect");
-      }
-
-      int returnValue = exec(Compiler.class, args.toArray(new String[0]), new File(outFile));
-      Assertions.assertEquals(1, returnValue, "RagConnect did not return with value 1");
-    } catch (IOException | InterruptedException e) {
-      e.printStackTrace();
-    }
+    String grammarFile = ERROR_DIRECTORY + DEFAULT_GRAMMAR_NAME + ".relast";
+    List<String> connectFiles = Arrays.stream(connectNames)
+        .map(connectName -> ERROR_DIRECTORY + connectName + ".connect")
+        .collect(Collectors.toList());
+    Path outPath = TestUtils.runCompiler(grammarFile, connectFiles, rootNode, ERROR_DIRECTORY, 1);
 
     final String startOfErrorsPattern = "SEVERE: Errors:";
-    String out = readFile(outFile, Charset.defaultCharset());
+    String out = readFile(outPath, Charset.defaultCharset());
     assertThat(out).contains(startOfErrorsPattern);
     out = out.substring(out.indexOf(startOfErrorsPattern) + 16);
 
-    String expected = readFile(expectedFile, Charset.defaultCharset());
-//    if (inFiles.size() == 1) {
-//      expected = expected.replace(FILENAME_PATTERN, name + ".connect");
-//    } else {
-//      for (int i = 0; i < inFiles.size(); i++) {
-//        expected = expected.replace(FILENAME_PATTERN + (i + 1), inFiles.get(i));
-//      }
-//    }
+    Path expectedPath = Paths.get(TestUtils.INPUT_DIRECTORY_PREFIX)
+        .resolve(ERROR_DIRECTORY)
+        .resolve(expectedName + ".expected");
+    String expected = readFile(expectedPath, Charset.defaultCharset());
     List<String> outList = Arrays.asList(out.split("\n"));
     Collections.sort(outList);
     List<String> expectedList = Arrays.stream(expected.split("\n"))
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4d7389dafd0b3e7ff8f96ccd9bb67bca8977cd9
--- /dev/null
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java
@@ -0,0 +1,38 @@
+package org.jastadd.ragconnect.tests;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.file.*;
+import java.util.Collections;
+
+/**
+ * Regression tests for fixed issues.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class RegressionTests {
+
+  private static final String REGRESSION_TEST_OUTPUT_DIRECTORY = "regression-test/";
+
+  @Test
+  public void issue27() throws IOException {
+    String grammarFile = "regression-tests/issue27/Test.relast";
+    String connectFile = "regression-tests/issue27/Test.connect";
+    grammarFile = ensureNoTrailingNewLine(grammarFile);
+    connectFile = ensureNoTrailingNewLine(connectFile);
+    TestUtils.runCompiler(grammarFile, Collections.singletonList(connectFile), "A", REGRESSION_TEST_OUTPUT_DIRECTORY, 0);
+  }
+
+  private String ensureNoTrailingNewLine(String inputFileSuffix) throws IOException {
+    int dotIndex = inputFileSuffix.lastIndexOf('.');
+    String outFileSuffix = inputFileSuffix.substring(0, dotIndex) + ".noNewLine" + inputFileSuffix.substring(dotIndex);
+    Path inputPath = Paths.get(TestUtils.INPUT_DIRECTORY_PREFIX).resolve(inputFileSuffix);
+    Path outputPath = Paths.get(TestUtils.INPUT_DIRECTORY_PREFIX).resolve(outFileSuffix);
+
+    String content = Files.readString(inputPath);
+    Files.writeString(outputPath, content.stripTrailing(), StandardOpenOption.CREATE);
+
+    return outFileSuffix;
+  }
+}
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java
index 2d08ccb376a6abaadf6643b32182c1ed5c10acda..c09059c8a66ca1cba262843ce30d4ce8ad0bc663 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java
@@ -1,13 +1,22 @@
 package org.jastadd.ragconnect.tests;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.jastadd.ragconnect.compiler.Compiler;
+import org.junit.jupiter.api.Assertions;
+
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 /**
@@ -17,7 +26,10 @@ import static org.junit.jupiter.api.Assertions.fail;
  */
 public class TestUtils {
 
+  private static final Logger logger = LogManager.getLogger(TestUtils.class);
   public static final double DELTA = 0.001d;
+  public static final String INPUT_DIRECTORY_PREFIX = "./src/test/01-input/";
+  public static final String OUTPUT_DIRECTORY_PREFIX = "./src/test/02-after-ragconnect/";
 
   public static String getMqttHost() {
     if (System.getenv("GITLAB_CI") != null) {
@@ -41,6 +53,41 @@ public class TestUtils {
     return 1883;
   }
 
+  public static Path runCompiler(String grammarFile, Iterable<String> connectFiles, String rootNode, String outputDirectory, int expectedReturnValue) {
+
+    assertThat(connectFiles).isNotEmpty();
+
+    Path outPath = Paths.get(OUTPUT_DIRECTORY_PREFIX)
+        .resolve(outputDirectory)
+        .resolve("Compiler.out");
+    ensureCreated(outPath.getParent());
+
+    try {
+      logger.debug("user.dir: {}", System.getProperty("user.dir"));
+      List<String> args = new ArrayList<>() {{
+        add("--o=" + OUTPUT_DIRECTORY_PREFIX + outputDirectory);
+        add("--rootNode=" + rootNode);
+        add("--verbose");
+        add(INPUT_DIRECTORY_PREFIX + grammarFile);
+      }};
+      connectFiles.forEach(connectFile -> args.add(INPUT_DIRECTORY_PREFIX + connectFile));
+
+      int returnValue = exec(Compiler.class, args.toArray(new String[0]), outPath.toFile());
+      Assertions.assertEquals(expectedReturnValue, returnValue, "RagConnect did not return with value " + expectedReturnValue);
+    } catch (IOException | InterruptedException e) {
+      fail(e);
+    }
+    return outPath;
+  }
+
+  private static void ensureCreated(Path directory) {
+    File directoryFile = directory.toFile();
+    if (directoryFile.exists() && directoryFile.isDirectory()) {
+      return;
+    }
+    assertTrue(directoryFile.mkdirs());
+  }
+
   public static int exec(Class<?> klass, String[] args, File err) throws IOException,
       InterruptedException {
     String javaHome = System.getProperty("java.home");
@@ -79,9 +126,9 @@ public class TestUtils {
     }
   }
 
-  public static String readFile(String path, Charset encoding)
+  public static String readFile(Path path, Charset encoding)
       throws IOException {
-    byte[] encoded = Files.readAllBytes(Paths.get(path));
+    byte[] encoded = Files.readAllBytes(path);
     return new String(encoded, encoding);
   }
 
diff --git a/relast-preprocessor b/relast-preprocessor
index b538a7f709167c5f56fe65e6d9e9f02179cacaef..02f8e35993dc3f62ab49e94f69a6dc27170660da 160000
--- a/relast-preprocessor
+++ b/relast-preprocessor
@@ -1 +1 @@
-Subproject commit b538a7f709167c5f56fe65e6d9e9f02179cacaef
+Subproject commit 02f8e35993dc3f62ab49e94f69a6dc27170660da
diff --git a/settings.gradle b/settings.gradle
index e7769874a5f3186274ceecbcd445feeb656cf9a4..8a597cfa491920744bb8b5e1d3f103fb4fc95bb1 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,9 @@
+pluginManagement {
+    plugins {
+        id 'org.jastadd' version '1.13.3'
+    }
+}
+
 rootProject.name = 'ragconnect'
 
 include 'relast-preprocessor'