Repository: shuttle-hq/synth (language: rust)

Issue:
panic: `Option::unwrap()` on a `None` value at core/src/graph/mod.rs:572:66
**Describe the bug**
Panic on calling `synth generate`

**To Reproduce**
1. Schema
users.json
```json
{
    "type": "array",
    "length": {
        "type": "number",
        "subtype": "u64",
        "constant": 1
    },
    "content": {
        "type": "object",
        "id": {
            "type": "number",
            "subtype": "u64",
            "id": {}
        }
    }
}
```
posts.json
```json
{
    "type": "array",
    "length": {
        "type": "number",
        "subtype": "u64",
        "constant": 1
    },
    "content": {
        "type": "object",
        "id": {
            "type": "number",
            "subtype": "u64",
            "id": {}
        },
        "user_id": {
            "type": "same_as",
            "ref": "users.content.id"
        }
    }
}
```
images.json
```json
{
    "type": "array",
    "length": {
        "type": "number",
        "subtype": "u64",
        "constant": 1
    },
    "content": {
        "type": "object",
        "id": {
            "type": "number",
            "subtype": "u64",
            "id": {}
        },
        "post_id": {
            "type": "same_as",
            "ref": "posts.content.id"
        }
    }
}
```
tags.json
```json
{
    "type": "array",
    "length": {
        "type": "number",
        "subtype": "u64",
        "constant": 1
    },
    "content": {
        "type": "object",
        "image": {
            "type": "same_as",
            "ref": "images.content.id"
        }
    }
}
```
2. See error
```console
$ synth generate ns --collection users
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', synth/core/src/graph/mod.rs:572:66
```

**Expected behavior**
Generated data or an error message explaining what's wrong with the schema.

**Environment (please complete the following information):**
 - OS: Ubuntu
 - Version: 21.04

**Additional context**
I was able to reproduce the bug both on the latest release and on master. The schema listed was the most minimal example I was able to find.


Discussion / hints:
Thank you @Heliozoa!

There seems to be a class of bugs that worked their way [on top of an old hack](https://github.com/getsynth/synth/blob/d1da60eafea5b7a0cb359d4d95e8f75631f92ccf/core/src/graph/mod.rs#L547).

I will get rid of the hack and this should solve this.

Fix patch:
diff --git a/core/src/compile/address.rs b/core/src/compile/address.rs
new file mode 100644
index 00000000..f04114ba
--- /dev/null
+++ b/core/src/compile/address.rs
@@ -0,0 +1,168 @@
+use std::collections::VecDeque;
+
+use crate::schema::FieldRef;
+
+/// A struct to hold the parsed components of the location of a node in a compiled tree.
+///
+/// An address of a node in the `Content` tree is an array of string names of child nodes, as
+/// declared by the node's [`Compile`](super::Compile) implementation.
+#[derive(Debug, Default, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
+pub struct Address(VecDeque<String>);
+
+impl std::fmt::Display for Address {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        let mut chunks = self.iter();
+        write!(f, "{}", chunks.next().unwrap_or("{top-level}"))?;
+        for chunk in chunks {
+            write!(f, ".{}", chunk)?;
+        }
+        Ok(())
+    }
+}
+
+impl Address {
+    #[inline]
+    pub fn new_root() -> Self {
+        Self(VecDeque::new())
+    }
+
+    #[inline]
+    pub fn is_root(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    pub fn root(&self) -> Self {
+        self.iter().map(|node| node.to_string()).take(1).collect()
+    }
+
+    #[inline]
+    pub fn iter(&self) -> impl DoubleEndedIterator<Item = &str> {
+        self.0.iter().map(|value| value.as_str())
+    }
+
+    #[inline]
+    pub fn deeper(&mut self) -> Option<String> {
+        self.0.pop_front()
+    }
+
+    #[inline]
+    pub fn shallower(&mut self) -> Option<String> {
+        self.0.pop_back()
+    }
+
+    #[inline]
+    pub fn into_shallower(mut self) -> Self {
+        self.shallower().unwrap();
+        self
+    }
+
+    #[inline]
+    pub fn within(&mut self, scope: &str) -> &mut Self {
+        self.0.push_front(scope.to_string());
+        self
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    #[inline]
+    pub fn into_within(mut self, scope: &str) -> Self {
+        self.within(scope);
+        self
+    }
+
+    #[inline]
+    pub fn at(&mut self, attribute: &str) -> &mut Self {
+        self.0.push_back(attribute.to_string());
+        self
+    }
+
+    #[inline]
+    pub fn into_at(mut self, attribute: &str) -> Self {
+        self.at(attribute);
+        self
+    }
+
+    pub fn as_local_to(&self, root: &Self) -> Option<Self> {
+        if root.0.len() > self.0.len() {
+            None
+        } else {
+            Some(
+                self.iter()
+                    .zip(root.iter())
+                    .skip_while(|(left, right)| left == right)
+                    .map(|(left, _)| left.to_string())
+                    .collect(),
+            )
+        }
+    }
+
+    pub fn as_in(&self, other: &Self) -> Option<Self> {
+        let mut out = self.clone();
+        for level in other.iter() {
+            if *level != out.deeper()? {
+                return None;
+            }
+        }
+        Some(out)
+    }
+
+    pub fn concat(&self, other: &Self) -> Self {
+        let mut out = self.clone();
+        out.extend(other.clone().into_iter());
+        out
+    }
+
+    pub fn relativize(&self, with: &Self) -> (Self, Self) {
+        let root = self.common_root(with);
+        let relative = self.as_in(&root).unwrap();
+        (root, relative)
+    }
+
+    pub fn common_root(&self, other: &Self) -> Self {
+        self.iter()
+            .zip(other.iter())
+            .take_while(|(left, right)| left == right)
+            .map(|(left, _)| left.to_string())
+            .collect()
+    }
+}
+
+impl std::iter::FromIterator<String> for Address {
+    #[inline]
+    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
+        Self(iter.into_iter().collect())
+    }
+}
+
+impl std::iter::Extend<String> for Address {
+    #[inline]
+    fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
+        self.0.extend(iter)
+    }
+}
+
+impl std::iter::IntoIterator for Address {
+    type Item = String;
+
+    type IntoIter = std::collections::vec_deque::IntoIter<String>;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.0.into_iter()
+    }
+}
+
+impl From<FieldRef> for Address {
+    #[inline]
+    fn from(field: FieldRef) -> Self {
+        field.into_iter().collect()
+    }
+}
\ No newline at end of file
diff --git a/core/src/compile/link.rs b/core/src/compile/link.rs
new file mode 100644
index 00000000..6e33e1dd
--- /dev/null
+++ b/core/src/compile/link.rs
@@ -0,0 +1,340 @@
+use synth_gen::prelude::{Generator, GeneratorState};
+
+use std::cell::RefCell;
+use std::ops::Range;
+use std::rc::Rc;
+use std::iter::IntoIterator;
+
+use crate::graph::prelude::Rng;
+
+pub struct Slice {
+    generation: usize,
+    start: usize
+}
+
+pub struct Tape<Y, R> {
+    slices: Vec<Slice>,
+    buffer: Vec<GeneratorState<Y, R>>,
+}
+
+impl<Y, R> Tape<Y, R> {
+    fn new() -> Self {
+        Self {
+            slices: Vec::new(),
+            buffer: Vec::new()
+        }
+    }
+
+    fn push_back(&mut self, state: GeneratorState<Y, R>) {
+        self.buffer.push(state)
+    }
+
+    fn get(&self, idx: usize) -> Option<&GeneratorState<Y, R>> {
+        self.buffer.get(idx)
+    }
+
+    fn reset(&mut self, idx: usize) {
+        let slice = self.slices.get_mut(idx).unwrap();
+        slice.generation += 1;
+        slice.start = self.buffer.len();
+    }
+
+    fn get_generation(&self, idx: usize) -> usize {
+        self.slices.get(idx).unwrap().generation
+    }
+
+    fn new_range(&self, idx: usize) -> Range<usize> {
+        self.slices.get(idx).unwrap().start..self.buffer.len()
+    }
+}
+
+pub type SharedTape<Y, R> = Rc<RefCell<Tape<Y, R>>>;
+
+pub(super) struct SliceRef<Y, R> {
+    index: usize,
+    tape: SharedTape<Y, R>
+}
+
+pub(super) type GeneratorSliceRef<G: Generator> = SliceRef<G::Yield, G::Return>;
+
+impl<Y, R> Clone for SliceRef<Y, R> {
+    fn clone(&self) -> Self {
+        Self {
+            index: self.index,
+            tape: self.tape.clone()
+        }
+    }
+}
+
+impl<Y, R> SliceRef<Y, R> {
+    pub(super) fn reset(&self) {
+        (*self.tape).borrow_mut().reset(self.index)
+    }
+
+    pub(super) fn new_view(&self) -> TapeView<Y, R> {
+        TapeView(TapeViewImpl {
+            slice: self.clone(),
+            generation: 0,
+            range: Range::default()
+        })
+    }
+
+    fn new_range(&self) -> Range<usize> {
+        (*self.tape).borrow().new_range(self.index)
+    }
+
+    fn get_generation(&self) -> usize {
+        (*self.tape).borrow().get_generation(self.index)
+    }
+}
+
+pub(super) struct RecorderImpl<G, Y, R> {
+    inner: G,
+    tape: SharedTape<Y, R>,
+}
+
+impl<G, Y, R> RecorderImpl<G, Y, R> {
+    fn new_slice(&self) -> SliceRef<Y, R> {
+        let index = {
+            let mut tape = (*self.tape).borrow_mut();
+            let slice = Slice {
+                generation: 0,
+                start: tape.buffer.len()
+            };
+            tape.slices.push(slice);
+            tape.slices.len() - 1
+        };
+        SliceRef {
+            index,
+            tape: self.tape.clone()
+        }
+    }
+}
+
+impl<G, Y, R> Generator for RecorderImpl<G, Y, R>
+    where
+        G: Generator<Yield = Y, Return = R>,
+        GeneratorState<Y, R>: Clone,
+{
+    type Yield = Y;
+
+    type Return = R;
+
+    fn next<RR: Rng>(&mut self, rng: &mut RR) -> GeneratorState<Self::Yield, Self::Return> {
+        let state = self.inner.next(rng);
+        (*self.tape).borrow_mut().push_back(state.clone());
+        state
+    }
+}
+
+impl<G, Y, R> RecorderImpl<G, Y, R>
+    where
+        G: Generator<Yield = Y, Return = R>,
+{
+    fn complete<RR: Rng>(&mut self, rng: &mut RR) {
+        #[allow(clippy::blocks_in_if_conditions)]
+        while {
+            let state = self.inner.next(rng);
+            let is_complete = state.is_complete();
+            (*self.tape).borrow_mut().push_back(state);
+            !is_complete
+        } {}
+    }
+}
+
+/// A generator that drives an inner generator and clones the result into a buffer before
+/// passing them through.
+///
+/// Closely related to [`TapeView`](TapeView).
+pub struct Recorder<G, Y, R>(pub(super) RecorderImpl<G, Y, R>);
+
+pub type GeneratorRecorder<G: Generator> = Recorder<G, G::Yield, G::Return>;
+
+impl<G, Y, R> Recorder<G, Y, R> {
+    pub(super) fn new_slice(&self) -> SliceRef<Y, R> {
+        self.0.new_slice()
+    }
+
+    pub(super) fn wrap(inner: G) -> Self {
+        Self(RecorderImpl {
+            inner,
+            tape: Rc::new(RefCell::new(Tape::new()))
+        })
+    }
+}
+
+impl<G, Y, R> Recorder<G, Y, R>
+    where
+        G: Generator<Yield = Y, Return = R>,
+{
+    fn complete<RR: Rng>(&mut self, rng: &mut RR) {
+        self.0.complete(rng)
+    }
+}
+
+pub(super) struct TapeViewImpl<Y, R> {
+    slice: SliceRef<Y, R>,
+    generation: usize,
+    range: Range<usize>
+}
+
+impl<Y, R> TapeViewImpl<Y, R> {
+    fn is_obsolete(&self) -> bool {
+        self.slice.get_generation() != self.generation
+    }
+
+    fn reset(&mut self) -> bool {
+        self.generation = self.slice.get_generation();
+        self.range = self.slice.new_range();
+        !self.range.is_empty()
+    }
+}
+
+impl<Y, R> Generator for TapeViewImpl<Y, R>
+where
+    GeneratorState<Y, R>: Clone,
+{
+    type Yield = Y;
+    type Return = Option<R>;
+
+    fn next<RR: Rng>(&mut self, rng: &mut RR) -> GeneratorState<Self::Yield, Self::Return> {
+        if self.is_obsolete() && !self.reset() {
+            return GeneratorState::Complete(None);
+        }
+
+        if let Some(idx) = self.range.next() {
+            (*self.slice.tape)
+                .borrow()
+                .get(idx)
+                .expect("a view's index was out of bound")
+                .clone()
+                .map_complete(Some)
+        } else if !self.reset() {
+            GeneratorState::Complete(None)
+        } else {
+            self.next(rng)
+        }
+    }
+}
+
+/// A generator that reads its output from a slice into the buffer managed by a
+/// [`Recorder`](Recorder).
+pub struct TapeView<Y, R>(pub(super) TapeViewImpl<Y, R>);
+
+pub(super) struct OrderedImpl<G, Y, R> {
+    is_complete: bool,
+    scope: Vec<SliceRef<Y, R>>,
+    children: Vec<(String, Recorder<G, Y, R>)>,
+    src: G,
+}
+
+impl<G, Y, R> Generator for OrderedImpl<G, Y, R>
+    where
+        G: Generator<Yield = Y, Return = R>,
+{
+    type Yield = Y;
+    type Return = R;
+
+    fn next<RR: Rng>(&mut self, rng: &mut RR) -> GeneratorState<Self::Yield, Self::Return> {
+        if !self.is_complete {
+            self.scope.iter_mut().for_each(|slice| {
+                slice.reset()
+            });
+            self.children.iter_mut().for_each(|(_, recorder)| {
+                recorder.complete(rng);
+            });
+            self.is_complete = true;
+        }
+        let state = self.src.next(rng);
+        self.is_complete = !state.is_complete();
+        state
+    }
+}
+
+/// A generator charged with setting the order of generation of a collection of inner
+/// generators.
+///
+/// This is essential to handle relations correctly as targets of references must always generate
+/// first.
+///
+/// `Ordered` is constructed by compiler after ordering children nodes according to their relative
+/// dependencies to one another.
+pub struct Ordered<G, Y, R>(pub(super) OrderedImpl<G, Y, R>);
+
+impl<G, Y, R> Ordered<G, Y, R> {
+    pub(super) fn new<S, C>(scope: S, children: C, src: G) -> Self
+    where
+        S: IntoIterator<Item = SliceRef<Y, R>>,
+        C: IntoIterator<Item = (String, Recorder<G, Y, R>)>
+    {
+        Self(OrderedImpl {
+            is_complete: false,
+            scope: scope.into_iter().collect(),
+            children: children.into_iter().collect(),
+            src
+        })
+    }
+}
+
+/// A generator compositor to establish relations ('links') between nodes of a generator tree.
+pub enum Link<G, Y, R> {
+    /// A recorder node.
+    Recorder(Recorder<G, Y, R>),
+    /// A view node.
+    View(TapeView<Y, R>),
+    /// An ordered node.
+    Ordered(Ordered<G, Y, R>),
+    /// A variant used in compilation as a placeholder prior to setting the node to its final
+    /// value.
+    Dummy
+}
+
+impl<G, Y, R> Generator for Link<G, Y, R>
+where
+    G: Generator<Yield = Y, Return = R>,
+    GeneratorState<Y, R>: Clone
+{
+    type Yield = Y;
+
+    type Return = Option<R>;
+
+    fn next<RR: Rng>(&mut self, rng: &mut RR) -> GeneratorState<Self::Yield, Self::Return> {
+        match self {
+            Self::Recorder(Recorder(recorder)) => recorder.next(rng).map_complete(Some),
+            Self::View(TapeView(view)) => view.next(rng),
+            Self::Ordered(Ordered(ordered)) => ordered.next(rng).map_complete(Some),
+            Self::Dummy => panic!("tried to generate values from a dummy")
+        }
+    }
+}
+
+impl<G, Y, R> Link<G, Y, R> {
+    pub fn new_dummy() -> Self {
+        Self::Dummy
+    }
+
+    pub fn iter_order(&self) -> Option<impl Iterator<Item = &str>> {
+        match self {
+            Self::Ordered(Ordered(OrderedImpl { children, .. })) => {
+                Some(children.iter().map(|(name, _)| name.as_str()))
+            },
+            _ => None
+        }
+    }
+}
+
+/// A trait for types that can own an inner [`Link`](Link).
+pub trait FromLink: Sized {
+    /// The type yielded by the [`Link`](Link).
+    type Yield;
+
+    /// The type returned by the [`Link`](Link).
+    type Return;
+
+    /// Build a `Self` from an instance of [`Link`](Link).
+    fn from_link(link: Link<Self, Self::Yield, Self::Return>) -> Self;
+
+    fn dummy() -> Self {
+        Self::from_link(Link::new_dummy())
+    }
+}
\ No newline at end of file
diff --git a/core/src/compile/mod.rs b/core/src/compile/mod.rs
index 64c56c48..1a515f1b 100644
--- a/core/src/compile/mod.rs
+++ b/core/src/compile/mod.rs
@@ -1,489 +1,67 @@
-use std::collections::{BTreeMap, BTreeSet, VecDeque};
-use std::iter::{DoubleEndedIterator, FromIterator, IntoIterator};
+//! convert [`Content`](crate::schema::Content) to [`Graph`](crate::graph::Graph).
+//!
+//! This module contains all the logic for taking a [`Content`](crate::schema::Content)
+//! to a [`Graph`](crate::graph::Graph). Where [`Content`](crate::schema::Content) is a user-facing
+//! specification of generators, [`Graph`](crate::graph::Graph) is the core data structure used in
+//! generating data. It is [`Graph`](crate::graph::Graph) that implements
+//! [`Generator`](synth_gen::prelude::Generator).
+//!
+//! While [`Content`](crate::schema::Content) is a tree, [`Graph`](crate::graph::Graph) is a DAG.
+//! Within a [`Graph`](crate::graph"::Graph), there may exist relations (encoded as `same_as` at
+//! the level of [`Content`](crate::schema::Content)) which force certain generators to track the
+//! values generated by others. This is done through wrapping these trackers in the [`Link`](Link)
+//! type.
+//!
+//! The core of this module is the [`Compiler`](Compiler)/[`Compile`](Compile) pair of traits.
+//! All [`Content`](crate::schema::Content) nodes implement [`Compile`](Compile) and get visited by
+//! [`Compiler`](Compiler)s.
+//!
+//! The main structure of this module is [`NamespaceCompiler`](NamespaceCompiler), which can be used
+//! to compile both [`Namespace`](crate::schema::Namespace) and [`Content`](crate::schema::Content)
+//! into [`Graph`](crate::graph::Graph).
+
+use std::collections::{BTreeMap, BTreeSet};
+use std::iter::IntoIterator;
 
 use anyhow::{Context, Result};
-use colored::Colorize;
-use synth_gen::prelude::*;
 
-mod utils;
-pub use utils::{Cursored, Driver, GeneratorOutput, Scoped, View};
+mod state;
+use state::{CompilerState, OutputState, Artifact, Source, Symbols};
 
-use crate::graph::{Graph, Unwrapped};
-use crate::schema::{Content, FieldRef, Namespace};
+mod address;
+use address::Address;
 
-macro_rules! says {
-    ($level:ident, $stage:expr, $color:ident, $content:expr$(, $arg:expr)*$(,)?) => {
-	$level!(target: "compiler", concat!("{} ", $content), $stage.bold().$color()$(, $arg)*)
-    };
-}
+pub mod link;
+pub use link::{FromLink, Link};
+use link::{Recorder, Ordered, GeneratorSliceRef, GeneratorRecorder};
 
-macro_rules! stage_1 {
-    ($content:expr$(, $arg:expr)*$(,)?) => {
-	says!(info, "stage 1", cyan, $content$(,$arg)*)
-    };
-}
-
-macro_rules! stage_2 {
-    ($content:expr$(, $arg:expr)*$(,)?) => {
-	says!(info, "stage 2", magenta, $content$(,$arg)*)
-    };
-}
+use crate::graph::Graph;
+use crate::schema::{Content, Namespace};
 
+/// A trait for visitors of the [`Content`](crate::schema::Content) tree.
+///
+/// Named children are visited (and built) by calling `build` and the value of a node at a
+/// different location in the tree (such as that required by `same_as`) is obtained by calling
+/// `get`.
 pub trait Compiler<'a> {
-    /// @brokad: API contract: do not inspect `Graph`
+    /// Build the child node called `field`.
     fn build(&mut self, field: &str, content: &'a Content) -> Result<Graph>;
 
-    /// @brokad: API contract: do not inspect `Graph`
-    fn get<S: Into<Scope>>(&mut self, field: S) -> Result<Graph>;
+    /// Access the built value of the node at address `field`.
+    fn get<S: Into<Address>>(&mut self, field: S) -> Result<Graph>;
 }
 
 pub trait Compile {
     fn compile<'a, C: Compiler<'a>>(&'a self, compiler: C) -> Result<Graph>;
 }
 
-#[derive(Default)]
-pub struct StructuredState<'a> {
-    children: BTreeMap<String, CompilerState<'a>>,
-    ordering: Vec<String>,
-}
-
-#[allow(dead_code)]
-impl<'a> StructuredState<'a> {
-    #[inline]
-    fn get(&self, field: &str) -> Option<&CompilerState<'a>> {
-        self.children.get(field)
-    }
-
-    #[inline]
-    fn get_mut(&mut self, field: &str) -> Option<&mut CompilerState<'a>> {
-        self.children.get_mut(field)
-    }
-
-    fn insert(&mut self, name: String, state: CompilerState<'a>) -> Option<CompilerState<'a>> {
-        if self.children.contains_key(&name) {
-            let (idx, _) = self
-                .ordering
-                .iter()
-                .enumerate()
-                .find(|(_, value)| **value == name)
-                .unwrap();
-            self.ordering.remove(idx);
-        }
-        self.ordering.push(name.clone());
-        self.children.insert(name, state)
-    }
-}
-
-impl<'a> std::iter::Extend<(String, CompilerState<'a>)> for StructuredState<'a> {
-    fn extend<T: IntoIterator<Item = (String, CompilerState<'a>)>>(&mut self, iter: T) {
-        for (name, state) in iter {
-            self.insert(name, state);
-        }
-    }
-}
-
-pub mod structured_state {
-    use super::*;
-
-    pub struct IntoIter<'a> {
-        children: BTreeMap<String, CompilerState<'a>>,
-        iter: std::vec::IntoIter<String>,
-    }
-
-    impl<'a> From<StructuredState<'a>> for IntoIter<'a> {
-        #[inline]
-        fn from(v: StructuredState<'a>) -> Self {
-            Self {
-                children: v.children,
-                iter: v.ordering.into_iter(),
-            }
-        }
-    }
-
-    impl<'a> Iterator for IntoIter<'a> {
-        type Item = (String, CompilerState<'a>);
-
-        #[inline]
-        fn next(&mut self) -> Option<Self::Item> {
-            self.iter
-                .next()
-                .and_then(|name| self.children.remove(&name).map(|state| (name, state)))
-        }
-    }
-}
-
-impl<'a> FromIterator<(String, CompilerState<'a>)> for StructuredState<'a> {
-    fn from_iter<I: IntoIterator<Item = (String, CompilerState<'a>)>>(iter: I) -> Self {
-        let (ordering, children) = iter
-            .into_iter()
-            .map(|(name, state)| (name.clone(), (name, state)))
-            .unzip();
-        Self { children, ordering }
-    }
-}
-
-impl<'a> IntoIterator for StructuredState<'a> {
-    type IntoIter = structured_state::IntoIter<'a>;
-    type Item = (String, CompilerState<'a>);
-
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        Self::IntoIter::from(self)
-    }
-}
-
-pub enum Source<'a> {
-    Namespace(&'a Namespace),
-    Content(&'a Content),
-}
-
-impl<'a> std::fmt::Display for Source<'a> {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        match self {
-            Self::Namespace(_) => write!(f, "namespace"),
-            Self::Content(_) => write!(f, "content"),
-        }
-    }
-}
-
-impl<'a> Source<'a> {
-    #[inline]
-    #[allow(dead_code)]
-    fn as_namespace(&self) -> Result<&'a Namespace> {
-        match self {
-            Self::Namespace(namespace) => Ok(namespace),
-            other => Err(failed!(
-                target: Release,
-                "source node type mismatch: expected namespace, found {}",
-                other
-            )),
-        }
-    }
-
-    #[inline]
-    #[allow(dead_code)]
-    fn as_content(&self) -> Result<&'a Content> {
-        match self {
-            Self::Content(content) => Ok(content),
-            other => Err(failed!(
-                target: Release,
-                "source node type mismatch: expected content, found {}",
-                other
-            )),
-        }
-    }
-}
-
-pub enum Artifact<G: Generator> {
-    Just(G),
-    Driver(Driver<G>),
-}
-
-impl Artifact<Graph> {
-    fn into_model(self) -> Graph {
-        match self {
-            Self::Just(g) => g,
-            Self::Driver(driver) => Graph::Driver(driver),
-        }
-    }
-}
-
-pub enum OutputState<G: Generator> {
-    Emptied,
-    Empty,
-    Some(Artifact<G>),
-}
-
-impl<G: Generator> Default for OutputState<G> {
-    fn default() -> Self {
-        Self::Empty
-    }
-}
-
-impl<G: Generator> OutputState<G> {
-    fn move_output(&mut self) -> Option<Artifact<G>> {
-        std::mem::replace(self, Self::Emptied).into_output()
-    }
-
-    fn set_output(&mut self, output: Artifact<G>) -> Option<Artifact<G>> {
-        std::mem::replace(self, Self::Some(output)).into_output()
-    }
-
-    fn into_output(self) -> Option<Artifact<G>> {
-        if let Self::Some(artifact) = self {
-            Some(artifact)
-        } else {
-            None
-        }
-    }
-
-    fn is_built(&self) -> bool {
-        matches!(self, Self::Emptied | Self::Some(_))
-    }
-}
-
-pub struct CompilerState<'a> {
-    src: Source<'a>,
-    compiled: OutputState<Graph>,
-    scope: StructuredState<'a>,
-    refs: BTreeSet<Scope>,
-}
-
-impl<'a> std::iter::Extend<(String, CompilerState<'a>)> for CompilerState<'a> {
-    #[inline]
-    fn extend<T: IntoIterator<Item = (String, CompilerState<'a>)>>(&mut self, iter: T) {
-        self.scope.extend(iter)
-    }
-}
-
-#[derive(Default, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
-pub struct Scope(VecDeque<String>);
-
-impl std::fmt::Display for Scope {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        let mut chunks = self.iter();
-        write!(f, "{}", chunks.next().unwrap_or("{top-level}"))?;
-        for chunk in chunks {
-            write!(f, ".{}", chunk)?;
-        }
-        Ok(())
-    }
-}
-
-#[allow(dead_code)]
-impl Scope {
-    #[inline]
-    fn new_root() -> Self {
-        Self(VecDeque::new())
-    }
-
-    #[inline]
-    fn is_root(&self) -> bool {
-        self.0.is_empty()
-    }
-
-    fn root(&self) -> Self {
-        self.iter().map(|node| node.to_string()).take(1).collect()
-    }
-
-    #[inline]
-    fn iter(&self) -> impl DoubleEndedIterator<Item = &str> {
-        self.0.iter().map(|value| value.as_str())
-    }
-
-    #[inline]
-    fn deeper(&mut self) -> Option<String> {
-        self.0.pop_front()
-    }
-
-    #[inline]
-    fn shallower(&mut self) -> Option<String> {
-        self.0.pop_back()
-    }
-
-    #[inline]
-    fn within(&mut self, scope: &str) -> &mut Self {
-        self.0.push_front(scope.to_string());
-        self
-    }
-
-    #[inline]
-    fn into_within(mut self, scope: &str) -> Self {
-        self.within(scope);
-        self
-    }
-
-    #[inline]
-    fn at(&mut self, attribute: &str) -> &mut Self {
-        self.0.push_back(attribute.to_string());
-        self
-    }
-
-    #[inline]
-    fn into_at(mut self, attribute: &str) -> Self {
-        self.at(attribute);
-        self
-    }
-
-    fn as_local_to(&self, root: &Self) -> Option<Self> {
-        if root.0.len() > self.0.len() {
-            None
-        } else {
-            Some(
-                self.iter()
-                    .zip(root.iter())
-                    .skip_while(|(left, right)| left == right)
-                    .map(|(left, _)| left.to_string())
-                    .collect(),
-            )
-        }
-    }
-
-    pub fn as_in(&self, other: &Self) -> Option<Self> {
-        let mut out = self.clone();
-        for level in other.iter() {
-            if *level != out.deeper()? {
-                return None;
-            }
-        }
-        Some(out)
-    }
-
-    fn concat(&self, other: &Self) -> Self {
-        let mut out = self.clone();
-        out.extend(other.clone().into_iter());
-        out
-    }
-
-    fn relativize(&self, with: &Self) -> (Self, Self) {
-        let root = self.common_root(with);
-        let relative = self.as_in(&root).unwrap();
-        (root, relative)
-    }
-
-    fn common_root(&self, other: &Self) -> Self {
-        self.iter()
-            .zip(other.iter())
-            .take_while(|(left, right)| left == right)
-            .map(|(left, _)| left.to_string())
-            .collect()
-    }
-}
-
-impl std::iter::FromIterator<String> for Scope {
-    #[inline]
-    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
-        Self(iter.into_iter().collect())
-    }
-}
-
-impl std::iter::Extend<String> for Scope {
-    #[inline]
-    fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
-        self.0.extend(iter)
-    }
-}
-
-impl std::iter::IntoIterator for Scope {
-    type Item = String;
-
-    type IntoIter = std::collections::vec_deque::IntoIter<String>;
-
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        self.0.into_iter()
-    }
-}
-
-impl From<FieldRef> for Scope {
-    #[inline]
-    fn from(field: FieldRef) -> Self {
-        field.into_iter().collect()
-    }
-}
-
-#[allow(dead_code)]
-impl<'a> CompilerState<'a> {
-    #[inline]
-    fn new(source: Source<'a>) -> Self {
-        Self {
-            src: source,
-            compiled: OutputState::default(),
-            scope: StructuredState::default(),
-            refs: BTreeSet::default(),
-        }
-    }
-
-    #[inline]
-    fn content(content: &'a Content) -> Self {
-        Self::new(Source::Content(content))
-    }
-
-    #[inline]
-    fn namespace(namespace: &'a Namespace) -> Self {
-        Self::new(Source::Namespace(namespace))
-    }
-
-    #[inline]
-    fn get(&self, field: &str) -> Option<&CompilerState<'a>> {
-        self.scope.get(field)
-    }
-
-    #[inline]
-    fn get_mut(&mut self, field: &str) -> Option<&mut CompilerState<'a>> {
-        self.scope.get_mut(field)
-    }
-
-    #[inline]
-    fn entry<'t>(&'t mut self, field: &str) -> Entry<'t, 'a> {
-        Entry {
-            node: self,
-            field: field.to_string(),
-        }
-    }
-
-    #[inline]
-    fn source(&self) -> &Source<'a> {
-        &self.src
-    }
-
-    #[inline]
-    fn move_output(&mut self) -> Option<Artifact<Graph>> {
-        self.compiled.move_output()
-    }
-
-    fn project(&mut self, mut to: Scope) -> Result<&mut Self> {
-        let mut projected = self;
-        while let Some(next) = to.deeper() {
-            projected = projected.get_mut(&next).ok_or_else(
-                || failed!(target: Release, Compilation => "unknown field: {}", next),
-            )?;
-        }
-        Ok(projected)
-    }
-}
-
-pub struct Entry<'t, 'a> {
-    node: &'t mut CompilerState<'a>,
-    field: String,
-}
-
-impl<'t, 'a> Entry<'t, 'a> {
-    #[allow(dead_code)]
-    fn or_build_within<F>(self, f: F) -> Result<&'t mut CompilerState<'a>>
-    where
-        for<'tt> F: FnOnce(&'tt mut CompilerState<'a>) -> ContentCompiler<'tt, 'a>,
-    {
-        if !self.node.compiled.is_built() {
-            f(self.node).compile()?;
-        }
-        if let Some(node) = self.node.get_mut(&self.field) {
-            return Ok(node);
-        }
-        Err(failed!(
-            target: Release,
-            "could not find field: {}",
-            self.field
-        ))
-    }
-
-    fn or_init(self, content: &'a Content) -> &'t mut CompilerState<'a> {
-        if !self.node.scope.children.contains_key(&self.field) {
-            self.node
-                .scope
-                .insert(self.field.clone(), CompilerState::content(content));
-        }
-        self.node.get_mut(&self.field).unwrap()
-    }
-}
-
 pub struct NamespaceCompiler<'a> {
-    state: CompilerState<'a>,
+    state: CompilerState<'a, Graph>,
     vtable: Symbols,
 }
 
 impl<'a> NamespaceCompiler<'a> {
-    pub fn new_at(state: CompilerState<'a>) -> Self {
+    fn new_at(state: CompilerState<'a, Graph>) -> Self {
         let vtable = Symbols::new();
         Self { state, vtable }
     }
@@ -499,148 +77,159 @@ impl<'a> NamespaceCompiler<'a> {
     }
 
     pub fn compile(mut self) -> Result<Graph> {
-        stage_1!("discovery");
-
         let crawler = Crawler {
-            cursor: &mut self.state,
-            table: &mut self.vtable,
-            position: Scope::new_root(),
+            state: &mut self.state,
+            symbols: &mut self.vtable,
+            position: Address::new_root(),
         };
 
         crawler.compile()?;
 
-        stage_2!("building");
+        let mut visits = vec![Address::new_root()];
 
-        let mut visits = VecDeque::<Scope>::new();
+        while let Some(address) = visits.pop() {
+            debug!("{}", address);
+            let next = {
+                let state = self.state.project(address.clone())?;
 
-        visits.push_back(Scope::new_root());
+                if state.output().is_built() {
+                    continue;
+                }
 
-        while let Some(next_scope) = visits.pop_back() {
-            stage_2!("{} nodes left", visits.len());
-            stage_2!("{}: entering scope", next_scope);
+                let mut targets = BTreeSet::new();
+                let mut pushbacks = BTreeSet::new();
+                for target in state.refs().iter() {
+                    // Direct references go first
+                    let is_built = self.vtable
+                        .is_built(&address, target)
+                        .ok_or_else(|| anyhow!("undefined reference to `{}` from `{}`", target, address))?;
+                    if !is_built {
+                        debug!("direct reference to `{}`", target);
+                        targets.insert(target.clone());
+                    }
 
-            let next = self.state.project(next_scope.clone())?;
-            let scope = &mut next.scope;
-            let compiled = &mut next.compiled;
-            let refs = &mut next.refs;
+                    // Then pushbacks to first child of the common root
+                    let (mut root, mut relative_to) = target.relativize(&address);
+                    if !relative_to.is_root() {
+                        let child = relative_to.deeper().unwrap();
+                        root.at(&child);
+                        let is_built = self.state
+                            .project(root.clone())?
+                            .output()
+                            .is_built();
+                        if !is_built && !relative_to.is_root() {
+                            debug!("pushback dependency to `{}`", root);
+                            pushbacks.insert(root);
+                        }
+                    }
+                }
 
-            if compiled.is_built() {
-                stage_2!("{}: already built", next_scope);
-                continue;
-            }
+                // Finally, we push direct descendents
+                let descents: BTreeSet<Address> = state
+                    .scope()
+                    .iter_keys()
+                    .filter_map(|child| {
+                        debug!("  {}", child);
+                        let is_built = state.get(&child).unwrap().output().is_built();
+                        let child_address = address.clone().into_at(&child);
+                        if !is_built
+                            && !targets.contains(&child_address)
+                            && !pushbacks.contains(&child_address) {
+                            Some(child_address)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect();
+
+                targets
+                    .into_iter()
+                    .chain(pushbacks.into_iter())
+                    .chain(descents.into_iter())
+                    .collect::<Vec<_>>()
+            };
 
-            let own_dependencies: Vec<Scope> = scope
-                .ordering
-                .iter()
-                .filter(|attr| !scope.children.get(*attr).unwrap().compiled.is_built())
-                .map(|attr| next_scope.clone().into_at(attr))
-                .collect();
-            stage_2!(
-                "{}: {} dependencies left",
-                next_scope,
-                own_dependencies.len()
-            );
-
-            let mut foreign_dependencies = Vec::new();
-            for reference in refs.iter() {
-                if !self.vtable.is_built(reference, &next_scope)? {
-                    foreign_dependencies.push(reference.clone());
+            if !next.is_empty() {
+                debug!("dependencies not satisfied: {:?}", next);
+                if matches!(self.state.project_mut(address.clone())?.output_mut().waiting(), OutputState::Waiting) {
+		    // This node was visited once and was waiting for dependencies to be built first,
+		    // then is now being visited a second time so is a dependency of itself.
+                    return Err(anyhow!("cycle detected at {}", address));
                 }
-            }
-            stage_2!(
-                "{}: {} references left",
-                next_scope,
-                foreign_dependencies.len()
-            );
-
-            if !own_dependencies.is_empty() || !foreign_dependencies.is_empty() {
-                visits.push_back(next_scope);
-                visits.extend(own_dependencies.into_iter().chain(foreign_dependencies));
+                visits.push(address);
+                visits.extend(next);
                 continue;
             }
 
-            let mut drivers = BTreeMap::new();
-
-            let ctx = self
-                .vtable
-                .get(&next_scope)
-                .map(|locals| {
-                    let keys: Vec<_> = locals.locals.keys().map(|key| key.to_string()).collect();
-                    keys.as_slice().join(", ")
-                })
-                .unwrap_or_else(|_| "{empty}".to_string());
-            stage_2!("{}: context extends to {}", next_scope, ctx);
+            if !address.is_root() {
+                let mut parent = address.clone();
+                let this = parent.shallower().unwrap();
+                // It is not necessary to order nodes that are not bound to be wrapped in `Ordered`
+                if self.vtable.contains(&parent) {
+                    self.state.project_mut(parent)?.scope_mut().push(this).unwrap();
+                }
+            }
 
+            let state = self.state.project_mut(address.clone())?;
+            let vtable = &mut self.vtable;
+            let mut children = BTreeMap::new();
             let content_compiler = ContentCompiler {
-                scope: next_scope.clone(),
-                cursor: next,
-                drivers: &mut drivers,
-                vtable: &mut self.vtable,
+                scope: address.clone(),
+                state,
+                children: &mut children,
+                vtable
             };
 
-            stage_2!("{}: building", next_scope);
-            let mut model = content_compiler
+            let mut node = content_compiler
                 .compile()
-                .with_context(|| format!("at `{}`", &next_scope))?;
-            stage_2!("{}: done", next_scope);
-
-            if let Ok(locals) = self.vtable.get(&next_scope) {
-                let cursors = locals.extract();
-                let mut order: Vec<_> = drivers.keys().cloned().collect();
-                order.sort_by(|left, right| {
-                    if locals.closure(left).contains(right) {
-                        std::cmp::Ordering::Less
-                    } else {
-                        std::cmp::Ordering::Greater
-                    }
-                });
-                model = Graph::Scoped(Scoped {
-                    cursors,
-                    drivers,
-                    order,
-                    src: Box::new(model),
-                    is_complete: true,
-                });
+                .with_context(|| format!("while trying to build `{}`", &address))?;
+
+            if let Some(local_table) = vtable.get(&address) {
+                // `node` must be wrapped in `Ordered`
+                let mut scope = local_table.values().map(|factory| {
+                    factory.get_source().unwrap()
+                }).collect::<Vec<_>>();
+                let mut ordered_children = Vec::new();
+                for child in state.scope().iter_ordered() {
+                    let (recorder, slice_ref) = children.remove(child).unwrap();
+                    scope.push(slice_ref);
+                    ordered_children.push((child.to_string(), recorder));
+                }
+                for (child, (recorder, slice_ref)) in children.into_iter() {
+                    scope.push(slice_ref);
+                    ordered_children.push((child, recorder));
+                }
+                node = Graph::from_link(Link::Ordered(Ordered::new(scope, ordered_children, node)));
             }
 
-            let artifact = if self.vtable.flattened.contains(&next_scope) {
-                stage_2!("{}: targetted", next_scope);
-                let (driver, mut cursor) = utils::channel(model);
-                for (root, tail) in self.vtable.paths(&next_scope) {
-                    // @brokad: keep this order for future proofing
-                    // when those become trees
-                    let next = cursor;
-                    cursor = next.subset();
-                    self.vtable.set(&root, &tail, next)?;
-                    stage_2!(
-                        "{}: shared node at {} to relative {} ready",
-                        next_scope,
-                        root,
-                        tail
-                    );
-                }
-                Artifact::Driver(driver)
+            let artifact = if vtable.targetted(&address) {
+                let recorder = Recorder::wrap(node);
+                vtable.paths(&address).into_iter().try_for_each(|(root, tail)| {
+                    debug!("setting source root=`{}` tail=`{}`", root, tail);
+                    vtable.set_source(&root, &tail, recorder.new_slice())
+                })?;
+                Artifact::from_recorder(recorder)
             } else {
-                Artifact::Just(model)
+                Artifact::just(node)
             };
 
-            next.compiled.set_output(artifact);
+            state.output_mut().set_output(artifact);
         }
 
-        Ok(self.state.move_output().unwrap().into_model())
+        Ok(self.state.move_output().unwrap().pack())
     }
 }
 
 pub struct ContentCompiler<'c, 'a: 'c> {
-    scope: Scope,
-    cursor: &'c mut CompilerState<'a>,
-    drivers: &'c mut BTreeMap<Scope, Driver<Graph>>,
+    scope: Address,
+    state: &'c mut CompilerState<'a, Graph>,
+    children: &'c mut BTreeMap<String, (GeneratorRecorder<Graph>, GeneratorSliceRef<Graph>)>,
     vtable: &'c mut Symbols,
 }
 
 impl<'c, 'a: 'c> ContentCompiler<'c, 'a> {
     fn compile(self) -> Result<Graph> {
-        match self.cursor.source() {
+        match self.state.source() {
             Source::Namespace(namespace) => namespace.compile(self),
             Source::Content(content) => content.compile(self),
         }
@@ -648,311 +237,52 @@ impl<'c, 'a: 'c> ContentCompiler<'c, 'a> {
 }
 
 impl<'c, 'a: 'c> Compiler<'a> for ContentCompiler<'c, 'a> {
-    fn build(&mut self, field: &str, _content: &'a Content) -> Result<Graph> {
-        stage_2!("{}: moving out of {}", self.scope, field);
-        let model = self
-            .cursor
+    fn build(&mut self, field: &str, _: &'a Content) -> Result<Graph> {
+        let mut child = self
+            .state
             .get_mut(field)
-            .ok_or_else(|| failed!(target: Release, Compilation => "undefined: {}", field))?
+            .expect("a previously visited child has disappeared")
             .move_output()
-            .ok_or_else(
-                || failed!(target: Release, Compilation => "dependency not satisfied: {}", field),
-            )?
-            .into_model();
-        let as_scope = Scope::new_root().into_within(field);
-        match self
-            .vtable
-            .get_mut(&self.scope)
-            .and_then(|locals| locals.get_mut(&as_scope))
-        {
-            Ok(factory) => {
-                // model is a driver
-                match model {
-                    Graph::Driver(driver) => self.drivers.insert(as_scope, driver),
-                    _ => {
-                        return Err(
-                            failed!(target: Release, Compilation => "where has the driver gone?"),
-                        )
-                    }
-                };
-                let as_view = factory.issue(&Scope::new_root())?.ok_or_else(
-                    || failed!(target: Release, Compilation => "reference not built: {}", field),
-                )?;
-                Ok(Graph::View(Unwrapped::wrap(as_view)))
-            }
-            Err(_) => Ok(model),
-        }
-    }
-
-    fn get<S: Into<Scope>>(&mut self, field: S) -> Result<Graph> {
-        let as_scope = field.into();
-        let view = self.vtable.issue(&as_scope, &self.scope)?.ok_or_else(
-            || failed!(target: Release, Compilation => "reference not built: {}", as_scope),
-        )?;
-        Ok(Graph::View(Unwrapped::wrap(view)))
-    }
-}
-
-pub struct ReferenceFactory<G: Generator> {
-    issued: BTreeSet<Scope>,
-    src: Option<Cursored<G>>,
-}
-
-impl<G: Generator> Default for ReferenceFactory<G> {
-    fn default() -> Self {
-        Self {
-            issued: BTreeSet::new(),
-            src: None,
-        }
-    }
-}
-
-impl<G> ReferenceFactory<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    fn issue(&mut self, to: &Scope) -> Result<Option<View<G>>> {
-        if !self.issued.contains(to) {
-            Err(failed!(target: Release, Compilation => "undeclared reference to {}", to))
-        } else {
-            Ok(self.src.as_ref().map(|cursored| cursored.view()))
-        }
-    }
-
-    fn is_built(&self) -> bool {
-        self.src.is_some()
-    }
-
-    fn set(&mut self, cursor: Cursored<G>) -> Option<Cursored<G>> {
-        std::mem::replace(&mut self.src, Some(cursor))
-    }
+            .expect("a built child was not available");
 
-    fn declare(&mut self, to: Scope) -> bool {
-        self.issued.insert(to)
-    }
-}
-
-pub struct LocalTable<G: Generator> {
-    locals: BTreeMap<Scope, ReferenceFactory<G>>,
-}
-
-impl<G> Default for LocalTable<G>
-where
-    G: Generator,
-{
-    fn default() -> Self {
-        Self {
-            locals: BTreeMap::new(),
+        if self.vtable.contains(&self.scope) {
+            // TODO: look into if we should use unpack here
+            let recorder = Recorder::wrap(child.pack());
+            let slice_ref = recorder.new_slice();
+            let view = slice_ref.new_view();
+            child = Artifact::from_view(view);
+            self.children.insert(field.to_string(), (recorder, slice_ref));
         }
-    }
-}
-
-impl<G> LocalTable<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    /// @brokad: fix panic
-    fn extract(&self) -> BTreeMap<Scope, Cursored<G>> {
-        self.locals
-            .iter()
-            .map(|(scope, factory)| (scope.clone(), factory.src.as_ref().unwrap().clone()))
-            .collect()
-    }
-
-    fn closure(&self, what: &Scope) -> BTreeSet<Scope> {
-        let what_root = what.root();
-        self.locals
-            .iter()
-            .filter(|(scope, _factory)| scope.root() == what_root)
-            .flat_map(|(_scope, factory)| factory.issued.iter().map(|issued| issued.root()))
-            .collect()
-    }
 
-    fn get(&self, to: &Scope) -> Result<&ReferenceFactory<G>> {
-        self.locals
-            .get(to)
-            .ok_or_else(|| failed!(target: Release, "undefined reference to {}", to))
+        Ok(child.pack())
     }
 
-    fn get_mut(&mut self, to: &Scope) -> Result<&mut ReferenceFactory<G>> {
-        self.locals
-            .get_mut(to)
-            .ok_or_else(|| failed!(target: Release, Compilation => "undeclared: {}", to))
-    }
-
-    #[allow(dead_code)]
-    fn ensure_no_cycle(&self, what: &Scope, to: &Scope) -> Result<()> {
-        let what_cl = self.closure(what);
-        let to_cl = self.closure(to);
-
-        let what_root = what.root();
-        if what_cl.contains(&what_root) {
-            return Err(failed!(
-                target: Release,
-                "the closure of {} contains {}",
-                what,
-                what_root
-            ));
-        }
-
-        let to_root = to.root();
-        if to_cl.contains(&to_root) {
-            return Err(failed!(
-                target: Release,
-                "the closure of {} contains {}",
-                to,
-                to_root
-            ));
-        }
-
-        if to_cl.intersection(&what_cl).next().is_some() {
-            return Err(failed!(
-                target: Release,
-                "the closures of {} and {} intersect each other",
-                what,
-                to
-            ));
-        }
-
-        Ok(())
-    }
-
-    fn issue(&mut self, what: &Scope, to: &Scope) -> Result<Option<View<G>>> {
-        self.locals
-            .get_mut(what)
-            .ok_or_else(|| failed!(target: Release, "undefined reference to {}", what))
-            .and_then(|factory| factory.issue(to))
-    }
-
-    fn declare(&mut self, what: Scope, to: Scope) -> Result<bool> {
-        if self.closure(&to).contains(&what.root()) {
-            Err(failed!(
-                target: Release,
-                "cycle detected: cannot add a reference to {} from {}",
-                what,
-                to
-            ))
-        } else {
-            let top_level = self.locals.entry(what.root()).or_default();
-            top_level.declare(Scope::new_root());
-            let local = self.locals.entry(what).or_default();
-            Ok(local.declare(to))
-        }
-    }
-}
-
-pub struct Symbols<G: Generator = Graph> {
-    flattened: BTreeSet<Scope>,
-    storage: BTreeMap<Scope, LocalTable<G>>,
-}
-
-impl<G> Symbols<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    fn new() -> Self {
-        Self {
-            flattened: BTreeSet::new(),
-            storage: BTreeMap::new(),
-        }
-    }
-
-    fn paths(&self, to: &Scope) -> Vec<(Scope, Scope)> {
-        let mut out = self
-            .storage
-            .iter()
-            .filter_map(|(what, table)| {
-                let rem = to.as_in(what)?;
-                table.locals.get(&rem)?;
-                Some((what.clone(), rem))
-            })
-            .collect::<Vec<_>>();
-        out.sort_by_key(|(start, _)| -(start.0.len() as i64));
-        out
-    }
-
-    fn is_built(&self, what: &Scope, to: &Scope) -> Result<bool> {
-        let (root, relative) = what.relativize(to);
-        Ok(self.get(&root)?.get(&relative)?.is_built())
-    }
-
-    fn declare(&mut self, what: Scope, to: Scope) -> Result<bool> {
-        let (root, relative) = what.relativize(&to);
-
-        if relative.is_root() {
-            // the reference is a cycle: `to` is referring to itself
-            return Err(failed!(
-                target: Release,
-                "cycle detected: {} is a direct ancestor to {}",
-                what,
-                to
-            ));
-        }
-
-        let relative_root = relative.root();
-        let relative_to = to.as_in(&root).unwrap();
-        let already = self
-            .storage
-            .entry(root.clone())
-            .or_default()
-            .declare(relative, relative_to)?;
-        self.flattened.insert(root.concat(&relative_root));
-        self.flattened.insert(what);
-        Ok(already)
-    }
-
-    fn get(&self, at: &Scope) -> Result<&LocalTable<G>> {
-        self.storage
-            .get(at)
-            .ok_or_else(|| failed!(target: Release, Compilation => "undeclared: {}", at))
-    }
-
-    fn get_mut(&mut self, at: &Scope) -> Result<&mut LocalTable<G>> {
-        self.storage
-            .get_mut(at)
-            .ok_or_else(|| failed!(target: Release, Compilation => "undeclared: {}", at))
-    }
-
-    fn set(
-        &mut self,
-        root: &Scope,
-        relative: &Scope,
-        cursor: Cursored<G>,
-    ) -> Result<Option<Cursored<G>>> {
-        Ok(self.get_mut(root)?.get_mut(relative)?.set(cursor))
-    }
-
-    fn issue(&mut self, what: &Scope, to: &Scope) -> Result<Option<View<G>>> {
-        let (root, relative_what) = what.relativize(to);
-        let relative_to = to.as_in(&root).unwrap();
-        self.get_mut(&root)
-            .with_context(|| anyhow!("looking for the common root to {} and {}", what, to))
-            .and_then(|local_table| local_table.issue(&relative_what, &relative_to))
+    fn get<S: Into<Address>>(&mut self, field: S) -> Result<Graph> {
+        let address = field.into();
+        let view = self.vtable.issue(&self.scope, &address)
+            .with_context(|| anyhow!("while trying to access a reference to `{}` at `{}`", address, self.scope))?;
+        Ok(Graph::from_link(Link::View(view)))
     }
 }
 
 pub struct Crawler<'t, 'a> {
-    cursor: &'t mut CompilerState<'a>,
-    table: &'t mut Symbols,
-    position: Scope,
+    state: &'t mut CompilerState<'a, Graph>,
+    symbols: &'t mut Symbols,
+    position: Address,
 }
 
 impl<'t, 'a: 't> Crawler<'t, 'a> {
     fn as_at(&mut self, field: &str, content: &'a Content) -> Crawler<'_, 'a> {
         let position = self.position.clone().into_at(field);
-        stage_1!("entering {}", position);
         Crawler {
-            cursor: self.cursor.entry(field).or_init(content),
-            table: self.table,
+            state: self.state.entry(field).or_init(content),
+            symbols: self.symbols,
             position,
         }
     }
 
     fn compile(self) -> Result<()> {
-        match self.cursor.source() {
+        match self.state.source() {
             Source::Namespace(namespace) => namespace.compile(self)?,
             Source::Content(content) => content.compile(self)?,
         };
@@ -963,17 +293,275 @@ impl<'t, 'a: 't> Crawler<'t, 'a> {
 impl<'t, 'a: 't> Compiler<'a> for Crawler<'t, 'a> {
     fn build(&mut self, field: &str, content: &'a Content) -> Result<Graph> {
         if let Err(err) = self.as_at(field, content).compile() {
-            warn!(target: "compiler", "{} node {} err'ed at visit: {}", "stage 1".bold().cyan(), field, err);
+            warn!("could not crawl into field `{}` at `{}`", field, self.position);
+            return Err(err);
+        }
+        Ok(Graph::dummy())
+    }
+
+    fn get<S: Into<Address>>(&mut self, target: S) -> Result<Graph> {
+        let target: Address = target.into();
+        self.symbols.declare(self.position.clone(), target.clone())?;
+        self.state.refs_mut().insert(target);
+        Ok(Graph::dummy())
+    }
+}
+
+#[cfg(test)]
+pub mod tests {
+    use crate::tests::complete;
+    use crate::graph::Value;
+
+    use synth_gen::prelude::*;
+
+    #[test]
+    fn compile_no_ref() {
+        let generator = generator!({
+            "type": "bool",
+            "constant": true
+        });
+        assert!(complete(generator).unwrap().as_bool().unwrap())
+    }
+
+    #[test]
+    fn compile_linear() {
+        let generator = generator!({
+            "type": "object",
+            "0": {
+                "type": "bool",
+                "constant": true
+            },
+            "1": "@0",
+            "2": "@1",
+            "3": "@2"
+        });
+        let value = complete(generator).unwrap();
+        let as_object = value.as_object().unwrap();
+        for i in 0..4 {
+            assert!(as_object.get(&i.to_string()).unwrap().as_bool().unwrap())
+        }
+    }
+
+    #[test]
+    fn compile_deep_linear() {
+        let generator = generator!({
+            "type": "object",
+            "0": {
+                "type": "object",
+                "0": {
+                    "type": "bool",
+                    "constant": true,
+                }
+            },
+            "1": {
+                "type": "object",
+                "0": "@0.0"
+            },
+            "2": {
+                "type": "object",
+                "0": "@1.0"
+            },
+            "3": {
+                "type": "object",
+                "0": "@2.0"
+            },
+            "4": {
+                "type": "object",
+                "0": "@3.0"
+            }
+        });
+        let value = complete(generator).unwrap();
+        let as_object = value.as_object().unwrap();
+        for i in 0..5 {
+            assert!(as_object.get(&i.to_string()).unwrap().as_object().unwrap().get("0").unwrap().as_bool().unwrap())
+        }
+    }
+
+    #[test]
+    fn compile_circle() {
+        let generator = try_generator!({
+            "type": "object",
+            "0": "@3",
+            "1": "@0",
+            "2": "@1",
+            "3": "@2"
+        });
+        assert!(generator.is_err())
+    }
+
+    #[test]
+    fn compile_deep_cycle() {
+        let generator = try_generator!({
+            "type": "object",
+            "0": {
+                "type": "object",
+                "0": "@4.0"
+            },
+            "1": {
+                "type": "object",
+                "0": "@0.0"
+            },
+            "2": {
+                "type": "object",
+                "0": "@1.0"
+            },
+            "3": {
+                "type": "object",
+                "0": "@2.0"
+            },
+            "4": {
+                "type": "object",
+                "0": "@3.0"
+            }
+        });
+        assert!(generator.is_err());
+    }
+
+    #[test]
+    fn compile_nested_cycle() {
+        let generator = try_generator!({
+            "type": "object",
+            "0": {
+                "type": "object",
+                "00": {
+                    "type": "object",
+                    "000": {
+                        "type": "object",
+                        "0000": "@1"
+                    },
+                    "001": "@0.00.000.0000"
+                },
+                "01": "@0.00.001"
+            },
+            "1": "@0.01"
+        });
+        assert!(generator.is_err())
+    }
+
+    #[test]
+    fn compile_nested_linear() {
+        let generator = generator!({
+            "type": "object",
+            "0": {
+                "type": "object",
+                "00": {
+                    "type": "object",
+                    "000": {
+                        "type": "object",
+                        "0000": {
+                            "type": "bool",
+                            "constant": true
+                        }
+                    },
+                    "001": "@0.00.000.0000"
+                },
+                "01": "@0.00.001"
+            },
+            "1": "@0.01"
+        });
+        assert!(complete(generator).unwrap().as_object().unwrap().get("1").unwrap().as_bool().unwrap())
+    }
+
+    #[test]
+    fn compile_star() {
+        let generator = generator!({
+            "type": "object",
+            "0": {
+                "type": "number",
+                "subtype": "u64",
+                "id": {}
+            },
+            "1": "@0",
+            "2": "@0",
+            "3": "@0",
+            "4": {
+                "type": "array",
+                "length": 42,
+                "content": "@0"
+            }
+        });
+        let value = complete(generator).unwrap();
+        let as_object = value.as_object().unwrap();
+        for i in 0..3 {
+            let number = as_object.get(&i.to_string()).unwrap().as_number().unwrap();
+            assert!(matches!(number, Number::U64(1)));
+        }
+        assert!(as_object.get("4").unwrap().as_array().unwrap().iter().all(|v| {
+            matches!(v.as_number().unwrap(), Number::U64(1))
+        }))
+    }
+
+    #[test]
+    fn compile_slices() {
+        let generator = generator!({
+            "type": "object",
+            "0": {
+                "type": "array",
+                "length": 4,
+                "content": {
+                    "type": "number",
+                    "subtype": "u64",
+                    "id": {}
+                }
+            },
+            "1": "@0.content",
+            "2": {
+                "type": "array",
+                "length": 4,
+                "content": "@0.content"
+            },
+            "22": "@2.content",
+            "3": {
+                "type": "array",
+                "length": 2,
+                "content": {
+                    "type": "array",
+                    "length": 2,
+                    "content": "@0.content"
+                }
+            },
+            "33": {
+                "type": "array",
+                "length": 4,
+                "content": {
+                    "type": "array",
+                    "length": "@3.content.content",
+                    "content": "@3.content.content"
+                }
+            }
+        });
+        let value = complete(generator).unwrap();
+        let as_object = value.as_object().unwrap();
+
+        let two = as_object.get("2").unwrap().as_array().unwrap();
+        for (i, v) in as_object.get("0").unwrap().as_array().unwrap().iter().enumerate() {
+            let ii = (i + 1) as u64;
+            assert_eq!(*v, Value::Number(Number::U64(ii)));
+            assert_eq!(*two.get(i).unwrap(), Value::Number(Number::U64(ii)));
         }
-        Ok(Graph::null())
-    }
 
-    fn get<S: Into<Scope>>(&mut self, field: S) -> Result<Graph> {
-        let as_scope: Scope = field.into();
-        stage_1!("linking {} to {}", as_scope, self.position);
-        self.table
-            .declare(as_scope.clone(), self.position.clone())?;
-        self.cursor.refs.insert(as_scope);
-        Ok(Graph::null())
+        assert!(matches!(as_object.get("1").unwrap().as_number().unwrap(), Number::U64(1)));
+
+        assert!(matches!(as_object.get("22").unwrap().as_number().unwrap(), Number::U64(1)));
+
+        let three = as_object.get("3").unwrap().as_array().unwrap();
+        let mut idx = 0;
+        for i in 0..2 {
+            let matches = three.get(i).unwrap().as_array().unwrap().iter().all(|v| {
+                idx += 1;
+                *v == Value::Number(Number::U64(idx))
+            });
+            assert!(matches);
+        }
+
+        let three_three = as_object.get("33").unwrap().as_array().unwrap();
+        let mut inner = (1..5).cycle();
+        for (i, v) in three_three.iter().enumerate() {
+            let v = v.as_array().unwrap();
+            assert_eq!(v.len(), i + 1);
+            v.iter().for_each(|vv| {
+                assert_eq!(*vv, Value::Number(Number::U64(inner.next().unwrap())));
+            });
+        }
     }
 }
diff --git a/core/src/compile/state.rs b/core/src/compile/state.rs
new file mode 100644
index 00000000..fcfed327
--- /dev/null
+++ b/core/src/compile/state.rs
@@ -0,0 +1,583 @@
+use anyhow::Result;
+
+use std::collections::{BTreeMap, BTreeSet};
+use std::iter::FromIterator;
+
+use synth_gen::prelude::*;
+
+use super::Address;
+use super::{Link, FromLink};
+use super::link::{TapeView, Recorder, SliceRef};
+
+use crate::schema::{Content, Namespace};
+
+/// A holder struct for the compiler's internal state of the children of a given node.
+///
+/// The collection of children can be ordered by the compiler - though not all of them need to be.
+/// The ordering is typically set as a result of dependencies between nodes.
+pub(super) struct StructuredState<'a, G: Generator> {
+    children: BTreeMap<String, CompilerState<'a, G>>,
+    ordering: Vec<String>,
+}
+
+#[allow(dead_code)]
+impl<'a, G: Generator> StructuredState<'a, G> {
+    #[inline]
+    pub(super) fn get(&self, field: &str) -> Option<&CompilerState<'a, G>> {
+        self.children.get(field)
+    }
+
+    #[inline]
+    pub(super) fn get_mut(&mut self, field: &str) -> Option<&mut CompilerState<'a, G>> {
+        self.children.get_mut(field)
+    }
+
+    pub(super) fn iter_keys(&self) -> impl Iterator<Item = String> {
+        let mut keys = self.children.keys().cloned().collect::<BTreeSet<_>>();
+        let mut ordered = Vec::new();
+        self.ordering.iter().for_each(|child| {
+            keys.remove(child);
+            ordered.push(child.clone());
+        });
+        ordered.into_iter().chain(keys.into_iter())
+    }
+
+    pub(super) fn iter_ordered(&self) -> std::slice::Iter<String> {
+        self.ordering.iter()
+    }
+
+    #[inline]
+    pub(super) fn push(&mut self, key: String) -> Option<()> {
+        self.children.get(&key)?;
+        self.ordering.push(key);
+        Some(())
+    }
+
+    #[inline]
+    pub(super) fn iter_values(&self) -> impl Iterator<Item = &CompilerState<'a, G>> {
+        self.iter_keys().map(move |key| self.children.get(&key).unwrap())
+    }
+
+    #[inline]
+    pub(super) fn iter(&self) -> impl Iterator<Item = (String, &CompilerState<'a, G>)> {
+        self.iter_keys().map(move |key| {
+            let value = self.get(&key).unwrap();
+            (key, value)
+        })
+    }
+
+    pub(super) fn insert(&mut self, name: String, state: CompilerState<'a, G>) -> Option<CompilerState<'a, G>> {
+        self.children.insert(name, state)
+    }
+}
+
+impl<'a, G: Generator> FromIterator<(String, CompilerState<'a, G>)> for StructuredState<'a, G> {
+    fn from_iter<I: IntoIterator<Item = (String, CompilerState<'a, G>)>>(iter: I) -> Self {
+        let (ordering, children) = iter
+            .into_iter()
+            .map(|(name, state)| (name.clone(), (name, state)))
+            .unzip();
+        Self { children, ordering }
+    }
+}
+
+impl<'a, G: Generator> IntoIterator for StructuredState<'a, G> {
+    type Item = (String, CompilerState<'a, G>);
+    type IntoIter = IntoIter<'a, G>;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        Self::IntoIter::from(self)
+    }
+}
+
+
+impl<'a, G: Generator> std::iter::Extend<(String, CompilerState<'a, G>)> for StructuredState<'a, G> {
+    fn extend<T: IntoIterator<Item = (String, CompilerState<'a, G>)>>(&mut self, iter: T) {
+        for (name, state) in iter {
+            self.insert(name, state);
+        }
+    }
+}
+
+impl<'a, G: Generator> Default for StructuredState<'a, G> {
+    fn default() -> Self {
+        Self {
+            children: BTreeMap::new(),
+            ordering: Vec::new(),
+        }
+    }
+}
+
+pub(super) struct IntoIter<'a, G: Generator> {
+    children: BTreeMap<String, CompilerState<'a, G>>,
+    iter: std::vec::IntoIter<String>,
+}
+
+impl<'a, G: Generator> From<StructuredState<'a, G>> for IntoIter<'a, G> {
+    #[inline]
+    fn from(v: StructuredState<'a, G>) -> Self {
+        Self {
+            children: v.children,
+            iter: v.ordering.into_iter(),
+        }
+    }
+}
+
+impl<'a, G: Generator> Iterator for IntoIter<'a, G> {
+    type Item = (String, CompilerState<'a, G>);
+
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter
+            .next()
+            .and_then(|name| self.children.remove(&name).map(|state| (name, state)))
+    }
+}
+
+pub(super) enum Source<'a> {
+    Namespace(&'a Namespace),
+    Content(&'a Content),
+}
+
+impl<'a> std::fmt::Display for Source<'a> {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        match self {
+            Self::Namespace(_) => write!(f, "namespace"),
+            Self::Content(_) => write!(f, "content"),
+        }
+    }
+}
+
+#[allow(dead_code)]
+impl<'a> Source<'a> {
+    #[inline]
+    pub(super) fn as_namespace(&self) -> Result<&'a Namespace> {
+        match self {
+            Self::Namespace(namespace) => Ok(namespace),
+            other => Err(failed!(
+                target: Release,
+                "source node type mismatch: expected namespace, found {}",
+                other
+            )),
+        }
+    }
+
+    #[inline]
+    pub(super) fn as_content(&self) -> Result<&'a Content> {
+        match self {
+            Self::Content(content) => Ok(content),
+            other => Err(failed!(
+                target: Release,
+                "source node type mismatch: expected content, found {}",
+                other
+            )),
+        }
+    }
+}
+
+pub(super) enum Artifact<G, Y, R> {
+    Just(G),
+    Link(Link<G, Y, R>),
+}
+
+impl<G, Y, R> Artifact<G, Y, R>
+where
+    G: Generator<Yield = Y, Return = R> + FromLink<Yield = Y, Return = R>
+{
+    pub(super) fn pack(self) -> G {
+        match self {
+            Self::Just(g) => g,
+            Self::Link(link) => G::from_link(link),
+        }
+    }
+
+    pub(super) fn just(inner: G) -> Self {
+        Self::Just(inner)
+    }
+
+    pub(super) fn from_view(view: TapeView<Y, R>) -> Self {
+        Self::Link(Link::View(view))
+    }
+
+    pub(super) fn from_recorder(recorder: Recorder<G, Y, R>) -> Self {
+        Self::Link(Link::Recorder(recorder))
+    }
+}
+
+pub(super) type GenArtifact<G: Generator> = Artifact<G, G::Yield, G::Return>;
+
+/// Holds the state of the build output of a node in the compiled DAG.
+///
+/// Typically follows `Empty -> Waiting -> Some(_) -> Emptied`.
+pub(super) enum OutputState<G: Generator> {
+    Emptied,
+    Empty,
+    Waiting,
+    Some(GenArtifact<G>),
+}
+
+impl<G: Generator> Default for OutputState<G> {
+    fn default() -> Self {
+        Self::Empty
+    }
+}
+
+impl<G: Generator> OutputState<G> {
+    pub(super) fn move_output(&mut self) -> Option<GenArtifact<G>> {
+        std::mem::replace(self, Self::Emptied).into_output()
+    }
+
+    pub(super) fn set_output(&mut self, output: GenArtifact<G>) -> Option<GenArtifact<G>> {
+        std::mem::replace(self, Self::Some(output)).into_output()
+    }
+
+    pub(super) fn into_output(self) -> Option<GenArtifact<G>> {
+        if let Self::Some(artifact) = self {
+            Some(artifact)
+        } else {
+            None
+        }
+    }
+
+    pub(super) fn waiting(&mut self) -> Self {
+        std::mem::replace(self, Self::Waiting)
+    }
+
+    pub(super) fn is_built(&self) -> bool {
+        matches!(self, Self::Emptied | Self::Some(_))
+    }
+}
+
+pub(super) struct CompilerState<'a, G: Generator> {
+    src: Source<'a>,
+    output: OutputState<G>,
+    scope: StructuredState<'a, G>,
+    refs: BTreeSet<Address>,
+}
+
+impl<'a, G: Generator> std::iter::Extend<(String, CompilerState<'a, G>)> for CompilerState<'a, G> {
+    #[inline]
+    fn extend<T: IntoIterator<Item = (String, CompilerState<'a, G>)>>(&mut self, iter: T) {
+        self.scope.extend(iter)
+    }
+}
+
+impl<'a, G: Generator> CompilerState<'a, G> {
+    #[inline]
+    pub(super) fn new(source: Source<'a>) -> Self {
+        Self {
+            src: source,
+            output: OutputState::default(),
+            scope: StructuredState::default(),
+            refs: BTreeSet::default(),
+        }
+    }
+
+    #[inline]
+    pub(super) fn content(content: &'a Content) -> Self {
+        Self::new(Source::Content(content))
+    }
+
+    #[inline]
+    pub(super) fn namespace(namespace: &'a Namespace) -> Self {
+        Self::new(Source::Namespace(namespace))
+    }
+
+    #[inline]
+    pub(super) fn get(&self, field: &str) -> Option<&Self> {
+        self.scope.get(field)
+    }
+
+    #[inline]
+    pub(super) fn get_mut(&mut self, field: &str) -> Option<&mut Self> {
+        self.scope.get_mut(field)
+    }
+
+    #[inline]
+    pub(super) fn output(&self) -> &OutputState<G> {
+        &self.output
+    }
+
+    #[inline]
+    pub(super) fn output_mut(&mut self) -> &mut OutputState<G> {
+        &mut self.output
+    }
+
+    #[inline]
+    pub(super) fn scope(&self) -> &StructuredState<'a, G> {
+        &self.scope
+    }
+
+    #[inline]
+    pub(super) fn scope_mut(&mut self) -> &mut StructuredState<'a, G> {
+        &mut self.scope
+    }
+
+    #[inline]
+    pub(super) fn refs(&self) -> &BTreeSet<Address> {
+        &self.refs
+    }
+
+    #[inline]
+    pub(super) fn refs_mut(&mut self) -> &mut BTreeSet<Address> {
+        &mut self.refs
+    }
+
+    #[inline]
+    pub(super) fn entry<'t>(&'t mut self, field: &str) -> Entry<'t, 'a, G> {
+        Entry {
+            node: self,
+            field: field.to_string(),
+        }
+    }
+
+    #[inline]
+    pub(super) fn source(&self) -> &Source<'a> {
+        &self.src
+    }
+
+    #[inline]
+    pub(super) fn move_output(&mut self) -> Option<GenArtifact<G>> {
+        self.output.move_output()
+    }
+
+    pub(super) fn project(&self, mut to: Address) -> Result<&Self> {
+        let mut projected = self;
+        while let Some(next) = to.deeper() {
+            projected = projected.get(&next).ok_or_else(
+                || failed!(target: Release, Compilation => "unknown field: {}", next),
+            )?;
+        }
+        Ok(projected)
+    }
+
+    pub(super) fn project_mut(&mut self, mut to: Address) -> Result<&mut Self> {
+        let mut projected = self;
+        while let Some(next) = to.deeper() {
+            projected = projected.get_mut(&next).ok_or_else(
+                || failed!(target: Release, Compilation => "unknown field: {}", next),
+            )?;
+        }
+        Ok(projected)
+    }
+}
+
+pub(super) struct Entry<'t, 'a, G: Generator> {
+    pub(super) node: &'t mut CompilerState<'a, G>,
+    pub(super) field: String,
+}
+
+impl<'t, 'a, G: Generator> Entry<'t, 'a, G> {
+    pub(super) fn or_init(self, content: &'a Content) -> &'t mut CompilerState<'a, G> {
+        if !self.node.scope.children.contains_key(&self.field) {
+            self.node
+                .scope
+                .insert(self.field.clone(), CompilerState::content(content));
+        }
+        self.node.get_mut(&self.field).unwrap()
+    }
+}
+
+/// A struct to store the views issued to nodes referring to a given recorder.
+pub(super) struct ReferenceFactory<G: Generator> {
+    issued: BTreeSet<Address>,
+    src: Option<SliceRef<G::Yield, G::Return>>,
+}
+
+impl<G: Generator> Default for ReferenceFactory<G> {
+    fn default() -> Self {
+        Self {
+            issued: BTreeSet::new(),
+            src: None,
+        }
+    }
+}
+
+impl<G> ReferenceFactory<G>
+    where
+        G: Generator,
+        GeneratorOutput<G>: Clone,
+{
+    fn declare(&mut self, from: Address) -> bool {
+        self.issued.insert(from)
+    }
+
+    fn issue(&mut self, from: &Address) -> Result<TapeView<G::Yield, G::Return>> {
+        if !self.issued.contains(from) {
+            Err(anyhow!("cannot issue a reference to `{}` unless it was previously declared", from))
+        } else if let Some(slice_ref) = self.src.as_ref() {
+            Ok(slice_ref.new_view())
+        } else {
+            Err(anyhow!("tried to issue a reference to `{}` before it was built", from))
+        }
+    }
+
+    fn is_ready(&self) -> bool {
+        self.src.is_some()
+    }
+
+    fn set_source(&mut self, inner: SliceRef<G::Yield, G::Return>) -> Option<SliceRef<G::Yield, G::Return>> {
+        std::mem::replace(&mut self.src, Some(inner))
+    }
+
+    pub(super) fn get_source(&self) -> Option<SliceRef<G::Yield, G::Return>> {
+        self.src.as_ref().cloned()
+    }
+}
+
+/// A table of addresses, relative to a local root of nodes targetted by a reference.
+///
+/// At each such address, we keep a [`ReferenceFactory`](ReferenceFactory).
+pub(super) struct LocalTable<G: Generator> {
+    locals: BTreeMap<Address, ReferenceFactory<G>>,
+}
+
+impl<G> Default for LocalTable<G>
+    where
+        G: Generator,
+{
+    fn default() -> Self {
+        Self {
+            locals: BTreeMap::new(),
+        }
+    }
+}
+
+impl<G> LocalTable<G>
+    where
+        G: Generator,
+        GeneratorOutput<G>: Clone,
+{
+    fn get(&self, to: &Address) -> Option<&ReferenceFactory<G>> {
+        self.locals.get(to)
+    }
+
+    pub(super) fn values(&self) -> impl Iterator<Item = &ReferenceFactory<G>> {
+        self.locals.values()
+    }
+
+    fn get_mut(&mut self, to: &Address) -> Option<&mut ReferenceFactory<G>> {
+        self.locals.get_mut(to)
+    }
+
+    fn declare(&mut self, from: Address, to: Address) -> Result<bool> {
+        let local = self.locals.entry(to).or_default();
+        Ok(local.declare(from))
+    }
+
+    fn issue(&mut self, from: &Address, to: &Address) -> Result<TapeView<G::Yield, G::Return>> {
+        self.get_mut(from)
+            .ok_or_else(|| anyhow!("no local table entry for `{}`", from))
+            .and_then(|factory| factory.issue(to))
+    }
+}
+
+/// The global table of addresses of nodes that are closest common ancestors of pairs of nodes
+/// referring to one another.
+///
+/// At each such node's address, we keep a [`LocalTable`](LocalTable).
+pub(super) struct Symbols<G: Generator = crate::graph::Graph> {
+    flattened: BTreeSet<Address>,
+    storage: BTreeMap<Address, LocalTable<G>>,
+}
+
+impl<G> Symbols<G>
+    where
+        G: Generator,
+        GeneratorOutput<G>: Clone,
+{
+    pub(super) fn new() -> Self {
+        Self {
+            flattened: BTreeSet::new(),
+            storage: BTreeMap::new(),
+        }
+    }
+
+    pub(super) fn get(&self, at: &Address) -> Option<&LocalTable<G>> {
+        self.storage.get(at)
+    }
+
+    pub(super) fn get_mut(&mut self, at: &Address) -> Option<&mut LocalTable<G>> {
+        self.storage.get_mut(at)
+    }
+
+    pub(super) fn paths(&self, to: &Address) -> Vec<(Address, Address)> {
+        self
+            .storage
+            .iter()
+            .filter_map(|(root, table)| {
+                let rem = to.as_in(root)?;
+                table.locals.get(&rem)?;
+                Some((root.clone(), rem))
+            })
+            .collect()
+    }
+
+    pub(super) fn is_built(&self, from: &Address, to: &Address) -> Option<bool> {
+        let (root, relative_to) = to.relativize(from);
+        Some(self.get(&root)?.get(&relative_to)?.is_ready())
+    }
+
+    pub(super) fn targetted(&self, address: &Address) -> bool {
+        self.flattened.contains(address)
+    }
+
+    pub(super) fn contains(&self, address: &Address) -> bool {
+        self.storage.contains_key(address)
+    }
+
+    pub(super) fn declare(&mut self, from: Address, to: Address) -> Result<bool> {
+        let (common_root, relative_to) = to.relativize(&from);
+        let relative_from = from.as_in(&common_root).unwrap();
+
+        if relative_to.is_root() {
+            // the reference is a cycle: `to` is referring to itself
+            return Err(failed!(
+                target: Release,
+                "cycle detected: {} is a direct ancestor to {}",
+                to,
+                from
+            ));
+        }
+
+        let already_declared = self
+            .storage
+            .entry(common_root)
+            .or_default()
+            .declare(relative_from, relative_to)?;
+
+        //self.flattened.insert(common_root.concat(&relative_to.root()));
+
+        self.flattened.insert(to);
+
+        Ok(already_declared)
+    }
+
+    pub(super) fn issue(&mut self, from: &Address, to: &Address) -> Result<TapeView<G::Yield, G::Return>> {
+        let (root, relative_what) = to.relativize(from);
+        let relative_to = from.as_in(&root).unwrap();
+        self.get_mut(&root)
+            .ok_or_else(|| anyhow!("no vtable entry for {}", root))
+            .and_then(|local_table| local_table.issue(&relative_what, &relative_to))
+    }
+
+    pub(super) fn set_source(
+        &mut self,
+        root: &Address,
+        relative: &Address,
+        source: SliceRef<G::Yield, G::Return>,
+    ) -> Result<()> {
+        if self.get_mut(root)
+            .ok_or_else(|| anyhow!("no vtable entry for {}", root))?
+            .get_mut(relative)
+            .ok_or_else(|| anyhow!("no local table entry for {}", relative))?
+            .set_source(source)
+            .map(|_| ())
+            .is_some() {
+            Err(anyhow!("source already set"))
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/core/src/compile/utils.rs b/core/src/compile/utils.rs
deleted file mode 100644
index 8d308907..00000000
--- a/core/src/compile/utils.rs
+++ /dev/null
@@ -1,540 +0,0 @@
-use synth_gen::prelude::*;
-
-use std::cell::RefCell;
-use std::collections::BTreeMap;
-use std::ops::Range;
-use std::rc::Rc;
-
-use bimap::BiBTreeMap;
-
-use super::Scope;
-
-pub type GeneratorOutput<G: Generator> = GeneratorState<G::Yield, G::Return>;
-
-pub type UniqueId = u64;
-#[derive(Debug, Clone)]
-struct UniqueRange<Idx> {
-    id: UniqueId,
-    range: Range<Idx>,
-}
-
-impl Eq for UniqueRange<usize> {}
-
-impl PartialEq for UniqueRange<usize> {
-    fn eq(&self, other: &Self) -> bool {
-        self.id == other.id
-    }
-}
-
-impl PartialOrd for UniqueRange<usize> {
-    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for UniqueRange<usize> {
-    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
-        (self.range.start, self.id).cmp(&(other.range.start, other.id))
-    }
-}
-
-#[derive(Clone, Debug)]
-struct UniqueMarker {
-    id: UniqueId,
-    marker: Marker,
-}
-
-impl Eq for UniqueMarker {}
-
-impl PartialEq for UniqueMarker {
-    fn eq(&self, other: &Self) -> bool {
-        self.id == other.id
-    }
-}
-
-impl PartialOrd for UniqueMarker {
-    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for UniqueMarker {
-    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
-        let self_left = self
-            .marker
-            .ranges
-            .right_values()
-            .next()
-            .map(|value| value.range.start);
-        let other_left = other
-            .marker
-            .ranges
-            .right_values()
-            .next()
-            .map(|value| value.range.start);
-        (self_left, self.id).cmp(&(other_left, other.id))
-    }
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
-struct Marker {
-    left: usize,
-    right: usize,
-    ranges: BiBTreeMap<UniqueId, UniqueRange<usize>>,
-}
-
-impl From<Range<usize>> for Marker {
-    fn from(r: Range<usize>) -> Self {
-        Self {
-            left: r.start,
-            right: r.end,
-            ranges: BiBTreeMap::new(),
-        }
-    }
-}
-
-impl Marker {
-    fn next_for(&mut self, range_id: UniqueId) -> Option<Option<usize>> {
-        match self.ranges.get_by_left(&range_id).cloned() {
-            Some(mut curr) => {
-                if curr.range.start == curr.range.end {
-                    curr.range = self.range();
-                }
-                let next = curr.range.next();
-                self.ranges.insert(range_id, curr);
-                Some(next)
-            }
-            None => None,
-        }
-    }
-
-    fn range(&self) -> Range<usize> {
-        self.left..self.right
-    }
-
-    fn new_range(&mut self) -> UniqueId {
-        let next_id = self.ranges.iter().last().map(|(k, _)| *k).unwrap_or(0) + 1;
-        self.ranges.insert(
-            next_id,
-            UniqueRange {
-                id: next_id,
-                range: self.range(),
-            },
-        );
-        next_id
-    }
-
-    fn flush(&mut self) {
-        self.left = self.right;
-    }
-
-    fn flush_to(&mut self, right: usize) {
-        self.right = right;
-        self.flush();
-    }
-
-    fn mark(&mut self, curr: usize) {
-        self.right = curr;
-        let mut updated_ranges = BiBTreeMap::new();
-        self.ranges.right_values().for_each(|value| {
-            updated_ranges.insert(
-                value.id,
-                UniqueRange {
-                    id: value.id,
-                    range: self.range(),
-                },
-            );
-        });
-        self.ranges = updated_ranges;
-    }
-}
-
-pub struct Buffered<G: Generator> {
-    inner: G,
-    buf: Vec<GeneratorOutput<G>>,
-    markers: BiBTreeMap<UniqueId, UniqueMarker>,
-    gc_threshold: usize,
-}
-
-impl<G> Buffered<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    fn new(inner: G) -> Self {
-        Self {
-            inner,
-            buf: Vec::new(),
-            markers: BiBTreeMap::new(),
-            gc_threshold: 1000000,
-        }
-    }
-
-    fn next_for(
-        &mut self,
-        marker_id: UniqueId,
-        range_id: UniqueId,
-    ) -> Option<Option<GeneratorOutput<G>>> {
-        self.garbage_collect();
-        let mut unique_marker = self.markers.get_by_left(&marker_id).cloned()?;
-        let next_idx = unique_marker.marker.next_for(range_id);
-        self.markers.insert(marker_id, unique_marker);
-        let next_idx = next_idx?;
-        debug!(
-            target: "compiler",
-            "view next for marker={} range={} at pos={}",
-            marker_id,
-            range_id,
-            next_idx.map(|idx| idx.to_string()).unwrap_or_else(|| "unknown".to_string())
-        );
-        Some(next_idx.map(|idx| self.buf.get(idx).unwrap().clone()))
-    }
-
-    fn new_range(&mut self, marker_id: UniqueId) -> Option<UniqueId> {
-        let mut unique_marker = self.markers.get_by_left(&marker_id).cloned()?;
-        let result = unique_marker.marker.new_range();
-        self.markers.insert(marker_id, unique_marker);
-        Some(result)
-    }
-
-    fn new_marker(&mut self) -> UniqueId {
-        let next_id = self.markers.iter().last().map(|(k, _)| *k).unwrap_or(0) + 1;
-        let idx = self.buf.len();
-        self.markers.insert(
-            next_id,
-            UniqueMarker {
-                id: next_id,
-                marker: Marker::from(idx..idx),
-            },
-        );
-        next_id
-    }
-
-    fn flush(&mut self, marker_id: UniqueId) -> Option<()> {
-        let curr = self.buf.len();
-        let mut unique_marker = self.markers.get_by_left(&marker_id).cloned()?;
-        unique_marker.marker.flush_to(curr);
-        self.markers.insert(marker_id, unique_marker);
-        Some(())
-    }
-
-    fn mark(&mut self, marker_id: UniqueId) -> Option<()> {
-        let curr = self.buf.len();
-        let mut unique_marker = self.markers.get_by_left(&marker_id).cloned()?;
-        unique_marker.marker.mark(curr);
-        self.markers.insert(marker_id, unique_marker);
-        Some(())
-    }
-
-    fn garbage_collect(&mut self) {
-        let threshold = self.gc_threshold;
-        let mut triggered = false;
-        if let Some(unique_marker) = self.markers.right_values().next() {
-            if let Some(unique_range) = unique_marker.marker.ranges.right_values().next() {
-                triggered = unique_range.range.start > threshold;
-            }
-        }
-        if triggered {
-            let mut updated_markers = BiBTreeMap::new();
-            self.markers.right_values().for_each(|unique_marker| {
-                let mut updated_marker = unique_marker.clone();
-                let mut updated_ranges = BiBTreeMap::new();
-                unique_marker
-                    .marker
-                    .ranges
-                    .right_values()
-                    .for_each(|value| {
-                        updated_ranges.insert(
-                            value.id,
-                            UniqueRange {
-                                id: value.id,
-                                range: value.range.start - threshold..value.range.end - threshold,
-                            },
-                        );
-                    });
-                let marker = &mut updated_marker.marker;
-                if marker.right < threshold {
-                    marker.flush_to(0);
-                } else {
-                    marker.right -= threshold;
-                    assert!(marker.left <= marker.right);
-                }
-                marker.ranges = updated_ranges;
-                updated_markers.insert(updated_marker.id, updated_marker);
-            });
-            self.markers = updated_markers;
-            assert!(self.buf.len() >= threshold);
-            self.buf.drain(0..threshold);
-        }
-    }
-
-    #[allow(dead_code)]
-    fn set_gc_threshold(&mut self, new_threshold: usize) {
-        self.gc_threshold = new_threshold;
-    }
-}
-
-impl<G> Generator for Buffered<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    type Yield = G::Yield;
-
-    type Return = G::Return;
-
-    fn next<R: Rng>(&mut self, rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
-        let next = self.inner.next(rng);
-        self.buf.push(next.clone());
-        next
-    }
-}
-
-pub struct Driver<G: Generator> {
-    src: Rc<RefCell<Buffered<G>>>,
-}
-
-impl<G> Generator for Driver<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    type Yield = G::Yield;
-
-    type Return = G::Return;
-
-    fn next<R: Rng>(&mut self, rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
-        self.src.borrow_mut().next(rng)
-    }
-}
-
-pub struct Cursored<G: Generator> {
-    src: Rc<RefCell<Buffered<G>>>,
-    marker_id: UniqueId,
-}
-
-impl<G> Cursored<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    pub fn view(&self) -> View<G> {
-        let marker_id = self.marker_id;
-        let range_id = self.src.borrow_mut().new_range(marker_id).unwrap();
-        View {
-            src: self.src.clone(),
-            marker_id,
-            range_id,
-        }
-    }
-
-    pub fn subset(&self) -> Self {
-        let marker_id = self.src.borrow_mut().new_marker();
-        Self {
-            src: self.src.clone(),
-            marker_id,
-        }
-    }
-
-    pub fn flush(&mut self) {
-        self.src.borrow_mut().flush(self.marker_id).unwrap();
-    }
-
-    pub fn mark(&mut self) {
-        self.src.borrow_mut().mark(self.marker_id).unwrap();
-    }
-}
-
-impl<G> Clone for Cursored<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    fn clone(&self) -> Self {
-        Cursored {
-            src: self.src.clone(),
-            marker_id: self.marker_id,
-        }
-    }
-}
-
-pub struct View<G: Generator> {
-    src: Rc<RefCell<Buffered<G>>>,
-    marker_id: UniqueId,
-    range_id: UniqueId,
-}
-
-impl<G> Generator for View<G>
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    type Yield = G::Yield;
-
-    type Return = Option<G::Return>;
-
-    fn next<R: Rng>(&mut self, _rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
-        let output = self
-            .src
-            .borrow_mut()
-            .next_for(self.marker_id, self.range_id)
-            .unwrap();
-        match output {
-            Some(GeneratorState::Yielded(yielded)) => GeneratorState::Yielded(yielded),
-            Some(GeneratorState::Complete(complete)) => GeneratorState::Complete(Some(complete)),
-            None => GeneratorState::Complete(None),
-        }
-    }
-}
-
-pub fn channel<G>(generator: G) -> (Driver<G>, Cursored<G>)
-where
-    G: Generator,
-    GeneratorOutput<G>: Clone,
-{
-    let mut buffered = Buffered::new(generator);
-    let marker_id = buffered.new_marker();
-    let src = Rc::new(RefCell::new(buffered));
-    let handler = Cursored {
-        src: src.clone(),
-        marker_id,
-    };
-    let driver = Driver { src };
-    (driver, handler)
-}
-
-pub struct Scoped<G: Generator> {
-    pub(super) cursors: BTreeMap<Scope, Cursored<G>>,
-    pub(super) drivers: BTreeMap<Scope, Driver<G>>,
-    pub(super) order: Vec<Scope>,
-    pub(super) src: Box<G>,
-    pub(super) is_complete: bool,
-}
-
-impl<G> Generator for Scoped<G>
-where
-    G: Generator,
-    G::Return: GeneratorResult,
-    GeneratorOutput<G>: Clone,
-{
-    type Yield = G::Yield;
-
-    type Return = G::Return;
-
-    #[allow(clippy::needless_collect)]
-    fn next<R: Rng>(&mut self, rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
-        if self.is_complete {
-            debug!("> scoped generator cycle BEGIN");
-            self.is_complete = false;
-            for scope in self.order.iter() {
-                let cursors = self
-                    .cursors
-                    .iter_mut()
-                    .filter(|(target, _)| target.as_in(scope).is_some())
-                    .map(|(scope, cursor)| {
-                        debug!(">> flush {}", scope);
-                        cursor.flush();
-                        (scope, cursor)
-                    })
-                    .collect::<Vec<_>>();
-                debug!(">>> drive {}", scope);
-                if let Err(err) = self.drivers.get_mut(scope).unwrap().complete(rng).into_result() {
-                    return GeneratorState::Complete(G::Return::from_err(err))
-                }
-                cursors.into_iter().for_each(|(scope, cursor)| {
-                    debug!(">> mark {}", scope);
-                    cursor.mark()
-                });
-            }
-        }
-        let next = self.src.next(rng);
-        if next.is_complete() {
-            self.is_complete = true;
-            debug!("< scoped generator cycle END");
-        }
-        next
-    }
-}
-
-#[cfg(test)]
-pub mod tests {
-    use rand::RngCore;
-    use std::borrow::{Borrow, BorrowMut};
-    use std::ops::Deref;
-
-    use super::*;
-
-    #[test]
-    fn buffered_gc() {
-        let mut rng = rand::thread_rng();
-        let initial_buf_len = 100;
-        // Single view
-        for threshold in [0, 1, 10] {
-            let seed = 1.yield_token();
-            let (mut driver, mut cursor) = channel(seed);
-            let mut view = cursor.view();
-            driver.src.deref().borrow_mut().set_gc_threshold(threshold);
-            // This fills up the buffer
-            cursor.flush();
-            for _ in 0..initial_buf_len {
-                driver.next(&mut rng);
-            }
-            assert_eq!(driver.src.deref().borrow().buf.len(), initial_buf_len);
-            cursor.mark();
-            // This advances `view`'s cursor in buffer, consuming its values
-            for _ in 0..initial_buf_len {
-                view.next(&mut rng);
-            }
-            assert!(
-                (threshold > 0 && driver.src.deref().borrow().buf.len() < initial_buf_len)
-                    || (threshold == 0 && driver.src.deref().borrow().buf.len() == initial_buf_len)
-            );
-        }
-        // Multiple views
-        for threshold in [0, 1, 10] {
-            struct TestView<G>
-            where
-                G: Generator,
-            {
-                view: Rc<RefCell<View<G>>>,
-                pos: usize,
-            }
-            let seed = 1.yield_token();
-            let (mut driver, mut cursor) = channel(seed);
-            let mut views = vec![];
-            let mut view_pos = vec![];
-            for _ in 0..10 {
-                let view = Rc::new(RefCell::new(cursor.view()));
-                view_pos.push(TestView {
-                    view: view.clone(),
-                    pos: 0,
-                });
-                views.push(view);
-            }
-            driver.src.deref().borrow_mut().set_gc_threshold(threshold);
-            // This fills up the buffer
-            cursor.flush();
-            for _ in 0..initial_buf_len {
-                driver.next(&mut rng);
-            }
-            cursor.mark();
-            while !view_pos.is_empty() {
-                let i: usize = (rng.next_u32() as usize) % view_pos.len();
-                view_pos[i].pos += 1;
-                view_pos[i]
-                    .borrow_mut()
-                    .view
-                    .deref()
-                    .borrow_mut()
-                    .next(&mut rng);
-                if view_pos[i].borrow().pos >= driver.src.deref().borrow().buf.len() - threshold {
-                    view_pos.remove(i);
-                }
-            }
-            assert!(
-                (threshold > 0 && driver.src.deref().borrow().buf.len() < initial_buf_len)
-                    || (threshold == 0 && driver.src.deref().borrow().buf.len() == initial_buf_len)
-            );
-        }
-    }
-}
diff --git a/core/src/graph/mod.rs b/core/src/graph/mod.rs
index 30897464..f562ba88 100644
--- a/core/src/graph/mod.rs
+++ b/core/src/graph/mod.rs
@@ -11,58 +11,10 @@ use sqlx::{Type, Encode, encode::IsNull};
 use synth_gen::prelude::*;
 use synth_gen::value::{Token, Tokenizer};
 
-use crate::compile::NamespaceCompiler;
-use crate::compile::{Driver, Scoped, View};
+use crate::compile::{NamespaceCompiler, Link};
 
 use crate::schema::{ChronoValueAndFormat, Namespace};
 
-macro_rules! derive_generator {
-    {
-	yield $yield:ty,
-	return $return:ty,
-	$vis:vis enum $id:ident {
-	    $(
-		$variant:ident($inner:ty$(,)?)$(,)?
-	    )*
-	}
-    } => {
-	$vis enum $id {
-	    $($variant($inner),)*
-	}
-
-	impl Generator for $id {
-	    type Yield = $yield;
-
-	    type Return = $return;
-
-	    fn next<R: Rng>(&mut self, rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
-		match self {
-		    $(
-			Self::$variant(inner) => inner.next(rng),
-		    )*
-		}
-	    }
-	}
-    };
-    {
-	yield $yield:ty,
-	return $return:ty,
-	$vis:vis struct $id:ident($inner:ty);
-    } => {
-	$vis struct $id($inner);
-
-	impl Generator for $id {
-	    type Yield = $yield;
-
-	    type Return = $return;
-
-	    fn next<R: Rng>(&mut self, rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
-		self.0.next(rng)
-	    }
-	}
-    }
-}
-
 pub mod prelude;
 use prelude::*;
 
@@ -540,11 +492,9 @@ derive_generator!(
         Object(ObjectNode),
         Array(ArrayNode),
         OneOf(OneOfNode),
-        Driver(Driver<Graph>),
-        View(Unwrapped<View<Graph>>),
-        Scoped(Scoped<Graph>),
         Series(SeriesNode),
-        Unique(UniqueNode)
+        Unique(UniqueNode),
+        Link(Box<LinkNode>)
     }
 );
 
@@ -562,60 +512,56 @@ impl Graph {
     }
 }
 
-pub type BoxedGraph = Box<Graph>;
+enum LinkNodeState {
+    YieldFrom,
+    Yield(Token),
+    Return(Value)
+}
 
-impl Generator for Box<Graph> {
-    type Yield = <Graph as Generator>::Yield;
+pub struct LinkNode(Link<Graph, Token, Result<Value, Error>>, LinkNodeState);
 
-    type Return = <Graph as Generator>::Return;
+impl Generator for Box<LinkNode> {
+    type Yield = Token;
+    type Return = Result<Value, Error>;
 
     fn next<R: Rng>(&mut self, rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
-        <Graph as Generator>::next(self, rng)
+        match std::mem::replace(&mut (*self).1, LinkNodeState::YieldFrom) {
+            LinkNodeState::YieldFrom => match self.0.next(rng) {
+                GeneratorState::Yielded(y) => GeneratorState::Yielded(y),
+                GeneratorState::Complete(Some(r)) => GeneratorState::Complete(r),
+                GeneratorState::Complete(None) => {
+                    (*self).1 = LinkNodeState::Yield(Token::Primitive(Primitive::Null(())));
+                    self.next(rng)
+                }
+            },
+            LinkNodeState::Yield(token) => {
+                (*self).1 = LinkNodeState::Return(Value::Null(()));
+                GeneratorState::Yielded(token)
+            },
+            LinkNodeState::Return(value) => GeneratorState::Complete(Ok(value))
+        }
     }
 }
 
-/// @brokad: use primitives instead, this is hacky...
-pub struct Unwrapped<G> {
-    inner: G,
-    is_complete: bool,
-    value: Option<Result<Value, Error>>,
-}
+impl crate::compile::FromLink for Graph {
+    type Yield = Token;
 
-impl Unwrapped<View<Graph>> {
-    pub fn wrap(inner: View<Graph>) -> Self {
-        Self {
-            inner,
-            is_complete: false,
-            value: None,
-        }
+    type Return = Result<Value, Error>;
+
+    fn from_link(link: Link<Self, Self::Yield, Self::Return>) -> Self {
+        Self::Link(Box::new(LinkNode(link, LinkNodeState::YieldFrom)))
     }
 }
 
-impl Generator for Unwrapped<View<Graph>> {
-    type Yield = Token;
+pub type BoxedGraph = Box<Graph>;
 
-    type Return = Result<Value, Error>;
+impl Generator for Box<Graph> {
+    type Yield = <Graph as Generator>::Yield;
+
+    type Return = <Graph as Generator>::Return;
 
     fn next<R: Rng>(&mut self, rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
-        if self.is_complete {
-            self.is_complete = false;
-            let value = std::mem::replace(&mut self.value, None).unwrap();
-            GeneratorState::Complete(value)
-        } else {
-            match self.inner.next(rng) {
-                GeneratorState::Yielded(yielded) => GeneratorState::Yielded(yielded),
-                GeneratorState::Complete(complete) => {
-                    self.is_complete = true;
-                    match complete {
-                        Some(value) => {
-                            self.value = Some(value);
-                            self.next(rng)
-                        }
-                        None => GeneratorState::Yielded(Token::Primitive(Primitive::Null(()))),
-                    }
-                }
-            }
-        }
+        <Graph as Generator>::next(self, rng)
     }
 }
 
@@ -631,7 +577,20 @@ impl Graph {
     pub fn from_namespace(ns: &Namespace) -> Result<Self> {
         NamespaceCompiler::new(ns)
             .compile()
-            .context("while compiling the namespace")
+            .context("cannot compile the namespace")
+    }
+
+    pub fn from_content(content: &Content) -> Result<Self> {
+        NamespaceCompiler::new_flat(content)
+            .compile()
+            .context("cannot compile the schema")
+    }
+
+    pub fn iter_ordered(&self) -> Option<impl Iterator<Item = &str>> {
+        match self {
+            Self::Link(box LinkNode(link, _)) => Some(link.iter_order()?),
+            _ => None
+        }
     }
 }
 
@@ -648,7 +607,8 @@ pub mod tests {
 
     #[test]
     fn schema_to_generator() {
-        let schema: Namespace = from_json!({
+        let schema: Namespace = schema!({
+            "type": "object",
             "users": {
                 "type": "array",
                 "length": 10,
@@ -791,7 +751,7 @@ pub mod tests {
                     },
                 }
             }
-        });
+        }).into_namespace().unwrap();
 
         let mut rng = rand::rngs::StdRng::seed_from_u64(0);
 
diff --git a/core/src/graph/unique.rs b/core/src/graph/unique.rs
index d2eeb4db..60c8b8be 100644
--- a/core/src/graph/unique.rs
+++ b/core/src/graph/unique.rs
@@ -1,5 +1,5 @@
 use crate::graph::prelude::{
-    Error, Generator, GeneratorState, Rng, Token, TryFilterMap, TryGeneratorExt, Value,
+    Error, Rng, Token, TryFilterMap, TryGeneratorExt, Value,
 };
 use crate::Graph;
 
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 28351624..72bcde42 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -8,6 +8,80 @@
 )]
 #![allow(type_alias_bounds)]
 
+#[macro_export]
+macro_rules! derive_generator {
+    {
+        yield $yield:ty,
+        return $return:ty,
+        $vis:vis enum $id:ident {
+            $(
+            $variant:ident($inner:ty$(,)?)$(,)?
+            )*
+        }
+    } => {
+        $vis enum $id {
+            $($variant($inner),)*
+        }
+
+        impl ::synth_gen::prelude::Generator for $id {
+            type Yield = $yield;
+
+            type Return = $return;
+
+            fn next<R: Rng>(&mut self, rng: &mut R) -> ::synth_gen::prelude::GeneratorState<Self::Yield, Self::Return> {
+                match self {
+                    $(
+                    Self::$variant(inner) => inner.next(rng),
+                    )*
+                }
+            }
+        }
+    };
+    {
+        yield $yield:ty,
+        return $return:ty,
+        $vis:vis struct $id:ident($inner:ty);
+    } => {
+        $vis struct $id($inner);
+
+        impl ::synth_gen::prelude::Generator for $id {
+            type Yield = $yield;
+
+            type Return = $return;
+
+            fn next<R: Rng>(&mut self, rng: &mut R) -> ::synth_gen::prelude::GeneratorState<Self::Yield, Self::Return> {
+                self.0.next(rng)
+            }
+        }
+    }
+}
+
+#[macro_export]
+macro_rules! schema {
+    {
+        $($inner:tt)*
+    } => {
+        serde_json::from_value::<crate::schema::Content>(serde_json::json!($($inner)*))
+            .expect("could not deserialize value into a schema")
+    }
+}
+
+
+#[macro_export]
+macro_rules! generator {
+    { $($inner:tt)* } => {
+        try_generator!($($inner)*).expect("could not compile the schema")
+    }
+}
+
+#[macro_export]
+macro_rules! try_generator {
+    { $($inner:tt)* } => {
+        crate::Graph::from_content(&schema!($($inner)*))
+    }
+}
+
+
 #[macro_use]
 extern crate log;
 
@@ -36,3 +110,21 @@ pub use graph::{Graph, Value};
 
 pub mod compile;
 pub use compile::{Compile, Compiler};
+
+#[cfg(test)]
+pub mod tests {
+    use rand::{SeedableRng, rngs::StdRng};
+    use synth_gen::prelude::Generator;
+
+    pub fn rng() -> StdRng {
+        StdRng::seed_from_u64(0)
+    }
+
+    pub fn complete<G: Generator>(mut generator: G) -> G::Return {
+        generator.complete(&mut rng())
+    }
+
+    pub fn complete_once<G: Generator>(generator: &mut G) -> G::Return {
+        generator.complete(&mut rng())
+    }
+}
\ No newline at end of file
diff --git a/core/src/schema/content/mod.rs b/core/src/schema/content/mod.rs
index dca860c9..339522bc 100644
--- a/core/src/schema/content/mod.rs
+++ b/core/src/schema/content/mod.rs
@@ -43,15 +43,15 @@ pub use categorical::{Categorical, CategoricalType};
 pub use number::Id;
 pub mod prelude;
 
-pub(crate) mod series;
+pub mod series;
+pub use series::SeriesContent;
 
 pub mod unique;
 pub use unique::{UniqueAlgorithm, UniqueContent};
 
 use prelude::*;
 
-use super::FieldRef;
-use crate::schema::content::series::SeriesContent;
+use super::{FieldRef, Namespace};
 
 pub trait Find<C> {
     fn find<I, R>(&self, reference: I) -> Result<&C>
@@ -281,6 +281,19 @@ impl Content {
         }
     }
 
+    pub fn into_namespace(self) -> Result<Namespace> {
+        match self {
+            Content::Object(ObjectContent { fields, .. }) => {
+                let mut namespace = Namespace::new();
+                for (key, content) in fields.into_iter() {
+                    namespace.put_collection(&key.parse()?, content)?;
+                }
+                Ok(namespace)
+            },
+            _ => Err(anyhow!("cannot convert a non-object content to a namespace"))
+        }
+    }
+
     pub fn accepts(&self, value: &Value) -> Result<()> {
         match self {
             Self::Unique(unique_content) => unique_content.content.accepts(value),
@@ -546,7 +559,7 @@ pub mod tests {
     use super::*;
 
     lazy_static! {
-        pub static ref USER_SCHEMA: Content = from_json!({
+        pub static ref USER_SCHEMA: Content = schema!({
             "type": "object",
             "skip_when_null": true,
             "user_id": {
@@ -627,6 +640,7 @@ pub mod tests {
                 }
             }
         });
+
         static ref USER: serde_json::Value = json!({
             "user_id" : 123,
             "type": "user",
@@ -700,7 +714,7 @@ pub mod tests {
 
     macro_rules! assert_idempotent {
 	($($inner:tt)*) => {
-	    let in_: DateTimeContent = from_json!($($inner)*);
+	    let in_: DateTimeContent = serde_json::from_value(json!($($inner)*)).unwrap();
 	    let out = serde_json::to_string(&in_).unwrap();
 	    assert_eq!(serde_json::from_str::<'_, DateTimeContent>(&out).unwrap(), in_);
 	}
diff --git a/core/src/schema/content/unique.rs b/core/src/schema/content/unique.rs
index 0b51288d..93b53fc5 100644
--- a/core/src/schema/content/unique.rs
+++ b/core/src/schema/content/unique.rs
@@ -11,6 +11,7 @@ pub enum UniqueAlgorithm {
     Hash { retries: Option<usize> },
 }
 
+#[allow(clippy::derivable_impls)]
 impl Default for UniqueAlgorithm {
     fn default() -> Self {
         Self::Hash { retries: None }
diff --git a/core/src/schema/inference/mod.rs b/core/src/schema/inference/mod.rs
index 1a77da59..eab83363 100644
--- a/core/src/schema/inference/mod.rs
+++ b/core/src/schema/inference/mod.rs
@@ -512,14 +512,14 @@ pub mod tests {
 
     #[test]
     fn merge_numbers() {
-        let mut master: NumberContent = from_json!({
+        let mut master: NumberContent = serde_json::from_value(json!({
             "subtype": "u64",
             "range": {
             "low": 0,
             "high": 10,
             "step": 1
             }
-        });
+        })).unwrap();
         let error_margin = f64::EPSILON;
 
         OptionalMergeStrategy
diff --git a/core/src/schema/mod.rs b/core/src/schema/mod.rs
index c83a99f6..717bc1e2 100644
--- a/core/src/schema/mod.rs
+++ b/core/src/schema/mod.rs
@@ -10,18 +10,6 @@ use serde::{
 };
 use serde_json::Value as JsonValue;
 
-#[allow(unused_macros)]
-macro_rules! from_json {
-    {
-	$($inner:tt)*
-    } => {
-	{
-	    let as_value = serde_json::json!( $($inner)* );
-	    serde_json::from_value(as_value).unwrap()
-	}
-    }
-}
-
 use crate::error::Error;
 
 pub mod inference;
diff --git a/core/src/schema/namespace.rs b/core/src/schema/namespace.rs
index 055a063f..0efa9f77 100644
--- a/core/src/schema/namespace.rs
+++ b/core/src/schema/namespace.rs
@@ -1,4 +1,3 @@
-use super::content::{FormatContent, ObjectContent, OneOfContent, StringContent};
 use super::inference::MergeStrategy;
 use super::{suggest_closest, ArrayContent, Content, FieldRef, Find, Name};
 use crate::compile::{Compile, Compiler};
@@ -11,15 +10,9 @@ use std::collections::BTreeMap;
 use std::convert::AsRef;
 use std::{default::Default, iter::FromIterator};
 
-use std::collections::{HashMap, VecDeque};
-use std::ops::Index;
-
 #[allow(dead_code)]
 type JsonObject = Map<String, Value>;
 
-//graph alies
-type NameGraph = HashMap<Name, Vec<Name>>;
-
 #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
 pub struct Namespace {
     #[serde(flatten)]
@@ -51,6 +44,10 @@ impl FromIterator<(Name, Content)> for Namespace {
 }
 
 impl Namespace {
+    pub fn new() -> Self {
+        Self::default()
+    }
+
     #[cfg(test)]
     pub fn accepts(&self, name: &Name, value: &Value) -> Result<()> {
         self.get_collection(name)?.accepts(value)
@@ -165,304 +162,18 @@ impl Namespace {
             Err(failed!(target: Release, NotFound => "no such collection: '{}'{}", name, suggest))
         }
     }
-    fn get_adj_list(&self) -> Result<Vec<(Name, Name)>> {
-        let mut list = Vec::new();
-        for (n, c) in self.collections.iter() {
-            get_list((n, c), &mut list);
-        }
-
-        list
-            .iter()
-            .try_for_each(|(t, s)| {
-                self.get_collection(s)
-                    .and_then(|_| self.get_collection(t))
-                    .map(|_| ())
-            })?;
-
-        Ok(list)
-    }
-
-    pub fn topo_sort(&self) -> Result<Vec<Name>> {
-        let lists: Vec<(Name, Name)> = self.get_adj_list()?;
-        let mut q: VecDeque<Name> = VecDeque::new();
-        let mut sorted: Vec<Name> = Vec::new();
-        let mut graph: NameGraph = NameGraph::new();
-        for v in &lists {
-            graph
-                .entry(v.0.clone())
-                .or_insert_with(Vec::new)
-                .push(v.1.clone());
-        }
-        info!("lists: {:?}", lists);
-        let mut in_degrees: BTreeMap<Name, usize> = BTreeMap::new();
-
-        for (p, c) in &lists {
-            *in_degrees.entry(c.clone()).or_insert(0) += 1;
-            in_degrees.entry(p.clone()).or_insert(0);
-        }
-
-        for n in &in_degrees {
-            if n.1 == &0 {
-                q.push_back(n.0.clone());
-            }
-        }
-
-        while let Some(name) = q.pop_front() {
-            sorted.push(name.clone());
-            info!("name: {:?}", name);
-            if graph.contains_key(&name) {
-                for out in graph.index(&name) {
-                    in_degrees.entry(out.clone()).and_modify(|v| *v -= 1);
-                    if in_degrees.iter().any(|v| v.1 == &0usize) {
-                        q.push_back(out.clone());
-                    }
-                }
-            };
-        }
-
-        if sorted.len() == in_degrees.keys().len() {
-            info!("{:?}", sorted);
-            //if the name has no same_as type field, it must still be in the list, but may come in any order, back or front
-            for name in self.collections.keys() {
-                if !sorted.contains(name) {
-                    sorted.push(name.clone());
-                }
-            }
-            Ok(sorted)
-        } else {
-            Err(failed!(target: Release, "there is a cycle in the schema: some collections refer to one another"))
-        }
-    }
 }
 
-fn get_list((n, c): (&Name, &Content), list: &mut Vec<(Name, Name)>) {
-    match c {
-        Content::Object(ObjectContent { fields, .. }) => {
-            for cont in fields.values() {
-                if let Content::SameAs(same) = cont {
-                    let (l, r) = (same.ref_.collection().clone(), n.clone());
-                    if l != r && !list.contains(&(l.clone(), r.clone())) {
-                        list.push((l, r));
-                    };
-                } else {
-                    get_list((n, cont), list);
-                }
-            }
-        }
-        Content::Array(ArrayContent { box content, .. }) => match content.clone() {
-            Content::Object(obj) => {
-                get_list((n, &Content::Object(obj)), list);
-            }
-            Content::Array(arr) => {
-                get_list((n, &Content::Array(arr)), list);
-            }
-            Content::SameAs(same) => {
-                get_list((n, &Content::SameAs(same)), list);
-            }
-            Content::OneOf(one) => {
-                get_list((n, &Content::OneOf(one)), list);
-            }
-            Content::String(s) => {
-                get_list((n, &Content::String(s)), list);
-            }
-            _ => {}
-        },
-        Content::OneOf(OneOfContent { variants }) => {
-            for variant in variants {
-                let box variant = variant.content.clone();
-                match variant {
-                    Content::Array(arr) => {
-                        get_list((n, &Content::Array(arr)), list);
-                    }
-                    Content::Object(obj) => {
-                        get_list((n, &Content::Object(obj)), list);
-                    }
-                    Content::OneOf(one) => {
-                        get_list((n, &Content::OneOf(one)), list);
-                    }
-                    Content::SameAs(same) => {
-                        get_list((n, &Content::SameAs(same)), list);
-                    }
-                    Content::String(s) => {
-                        get_list((n, &Content::String(s)), list);
-                    }
-                    _ => {}
-                }
-            }
-        }
-        Content::SameAs(same_as_content) => {
-            let pair = (same_as_content.ref_.collection().clone(), n.clone());
-            if pair.0 != pair.1 && !list.contains(&pair) {
-                list.push(pair);
-            };
-        }
-        Content::String(StringContent::Format(form)) => {
-            //the only variant of string that can hold a content
-            let FormatContent { ref arguments, .. } = form;
-            for (_, c) in arguments.iter() {
-                get_list((n, c), list);
-            }
-        }
-        _ => {}
-    }
-}
 impl Compile for Namespace {
     fn compile<'a, C: Compiler<'a>>(&'a self, mut compiler: C) -> Result<Graph> {
-        // TODO: needs to wrap each top-level attribute in a variable size array model
-        let sorted_ns = self
-            .topo_sort()?;
-        let object_node = sorted_ns
+        let object_node = self
             .iter()
-            .map(|name| {
-                let field = self.collections.get(name).expect("field should be there");
+            .map(|(name, content)| {
                 compiler
-                    .build(name.as_ref(), field)
+                    .build(name.as_ref(), content)
                     .map(|graph| KeyValueOrNothing::always(name.as_ref(), graph))
             })
             .collect::<Result<_>>()?;
         Ok(Graph::Object(object_node))
     }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::schema::BoolContent;
-    use crate::schema::Content;
-    #[test]
-    fn test_sort_simple() {
-        let mut namespace = Namespace {
-            collections: BTreeMap::new(),
-        };
-        let ref1: FieldRef = "visitors.address.postcode".parse().unwrap();
-        let ref2: FieldRef = "daughters.address.postcode".parse().unwrap();
-
-        namespace
-            .put_collection(
-                &"users".parse::<Name>().unwrap(),
-                Content::SameAs(crate::schema::SameAsContent { ref_: ref1 }),
-            )
-            .unwrap();
-        namespace
-            .put_collection(
-                &"sons".parse::<Name>().unwrap(),
-                Content::SameAs(crate::schema::SameAsContent { ref_: ref2 }),
-            )
-            .unwrap();
-        namespace
-            .put_collection(
-                &"visitors".parse::<Name>().unwrap(),
-                Content::Bool(BoolContent::Constant(true)),
-            )
-            .unwrap();
-        namespace
-            .put_collection(
-                &"daughters".parse::<Name>().unwrap(),
-                Content::Bool(BoolContent::Constant(false)),
-            )
-            .unwrap();
-        println!("sorted: {:?}", namespace.topo_sort());
-        let sorted = namespace.topo_sort().unwrap();
-        let length = sorted.len();
-        for i in 0..length {
-            assert!(check_dep(&sorted[..i], &namespace))
-        }
-    }
-
-    #[test]
-    fn test_sort_complex() {
-        let mut namespace = Namespace {
-            collections: BTreeMap::new(),
-        };
-        let ref1: FieldRef = "visitors.address.postcode".parse().unwrap();
-
-        namespace
-            .put_collection(
-                &"users".parse::<Name>().unwrap(),
-                Content::SameAs(crate::schema::SameAsContent { ref_: ref1.clone() }),
-            )
-            .unwrap();
-        namespace
-            .put_collection(
-                &"sons".parse::<Name>().unwrap(),
-                Content::SameAs(crate::schema::SameAsContent { ref_: ref1 }),
-            )
-            .unwrap();
-        println!("sorted: {:?}", namespace.topo_sort());
-        namespace
-            .put_collection(
-                &"visitors".parse::<Name>().unwrap(),
-                Content::Bool(BoolContent::Constant(true)),
-            )
-            .unwrap();
-        namespace
-            .put_collection(
-                &"daughters".parse::<Name>().unwrap(),
-                Content::Bool(BoolContent::Constant(false)),
-            )
-            .unwrap();
-
-        println!("sorted: {:?}", namespace.topo_sort());
-        let sorted = namespace.topo_sort().unwrap();
-        let length = sorted.len();
-        for i in 0..length {
-            assert!(check_dep(&sorted[..i], &namespace))
-        }
-    }
-
-    #[test]
-    fn test_sort_cycle() {
-        let mut namespace = Namespace {
-            collections: BTreeMap::new(),
-        };
-        let ref1: FieldRef = "visitors.address.postcode".parse().unwrap();
-        let ref2: FieldRef = "users.address.postcode".parse().unwrap();
-        //            let ref3: FieldRef = "winners.address.postcode".parse().unwrap();
-
-        namespace
-            .put_collection(
-                &"users".parse::<Name>().unwrap(),
-                Content::SameAs(crate::schema::SameAsContent { ref_: ref1 }),
-            )
-            .unwrap();
-        namespace
-            .put_collection(
-                &"visitors".parse::<Name>().unwrap(),
-                Content::SameAs(crate::schema::SameAsContent { ref_: ref2 }),
-            )
-            .unwrap();
-        println!("sorted: {:?}", namespace.topo_sort());
-        assert!(namespace.topo_sort().is_err());
-    }
-
-    #[test]
-    fn test_sort_not_exist() {
-        let mut namespace = Namespace {
-            collections: BTreeMap::new(),
-        };
-        let ref1: FieldRef = "i_dont_exist.address.postcode".parse().unwrap();
-
-        namespace
-            .put_collection(
-                &"users".parse::<Name>().unwrap(),
-                Content::SameAs(crate::schema::SameAsContent { ref_: ref1 }),
-            )
-            .unwrap();
-        println!("sorted: {:?}", namespace.topo_sort());
-        assert!(namespace.topo_sort().is_err());
-    }
-
-    //helper method for checking sorted dependencies
-    fn check_dep(list: &[Name], ns: &Namespace) -> bool {
-        let (last, list) = match list.split_last() {
-            Some(n) => n,
-            None => return true,
-        };
-        let c = ns.get_collection(last).unwrap();
-        if let Content::SameAs(same) = c {
-            list.contains(same.ref_.collection()) && check_dep(list, ns)
-        } else {
-            true
-        }
-    }
-}
+}
\ No newline at end of file
diff --git a/gen/src/lib.rs b/gen/src/lib.rs
index fc3da169..53317efd 100644
--- a/gen/src/lib.rs
+++ b/gen/src/lib.rs
@@ -68,31 +68,7 @@ pub enum GeneratorState<Y, R> {
     Complete(R),
 }
 
-/*
-impl<Y, R> std::ops::Try for GeneratorState<Y, R>
-where
-    R: std::ops::Try
-{
-    type Ok = R::Ok;
-
-    type Error = R::Error;
-
-    fn into_result(self) -> Result<Self::Ok, Self::Error> {
-        match self {
-        GeneratorState::Complete(r) => r.into_result(),
-        GeneratorState::Yielded(_) => todo!()
-    }
-    }
-
-    fn from_error(v: Self::Error) -> Self {
-        Self::Complete(R::from_error(v))
-    }
-
-    fn from_ok(v: Self::Ok) -> Self {
-        Self::Complete(R::from_ok(v))
-    }
-}
-*/
+pub type GeneratorOutput<G: Generator> = GeneratorState<G::Yield, G::Return>;
 
 impl<Y, R> GeneratorState<Y, R> {
     pub fn is_yielded(&self) -> bool {
diff --git a/gen/src/prelude.rs b/gen/src/prelude.rs
index 7fbb10c4..2a6af8a9 100644
--- a/gen/src/prelude.rs
+++ b/gen/src/prelude.rs
@@ -14,7 +14,7 @@ pub use crate::value::{
 };
 pub use crate::{
     FallibleGenerator, FallibleGeneratorExt, Generator, GeneratorExt, GeneratorResult,
-    TryGenerator, TryGeneratorExt,
+    TryGenerator, TryGeneratorExt, GeneratorOutput
 };
 
 pub use rand::Rng;
diff --git a/nix/overlay.nix b/nix/overlay.nix
index 59a7d1b0..ef9af0e4 100644
--- a/nix/overlay.nix
+++ b/nix/overlay.nix
@@ -4,7 +4,7 @@
 self: super: {
   synthPackages = {
     rustToolchain = super.rustChannelOf {
-      date = "2021-09-01";
+      date = "2021-09-15";
       channel = "nightly";
     };
 
diff --git a/synth/src/cli/export.rs b/synth/src/cli/export.rs
index fc1daf23..469a8d7e 100644
--- a/synth/src/cli/export.rs
+++ b/synth/src/cli/export.rs
@@ -8,7 +8,7 @@ use std::convert::TryFrom;
 use crate::cli::mongo::MongoExportStrategy;
 use crate::cli::mysql::MySqlExportStrategy;
 use crate::datasource::DataSource;
-use crate::sampler::Sampler;
+use crate::sampler::{Sampler, SamplerOutput};
 use async_std::task;
 use synth_core::{Name, Namespace, Value};
 
@@ -85,23 +85,15 @@ pub(crate) fn create_and_insert_values<T: DataSource>(
         sampler.sample_seeded(params.collection_name.clone(), params.target, params.seed)?;
 
     match values {
-        Value::Array(collection) => {
+        SamplerOutput::Collection(collection) => {
             insert_data(datasource, params.collection_name.unwrap().to_string(), &collection)
         }
-        Value::Object(namespace_json) => {
-            let names = params.namespace.topo_sort()?.into_iter().map(|name| name.to_string());
-            for n in names {
-                let collection = namespace_json.get(&n.to_string())
-                    .expect("did not find Value for name")
-                    .as_array()
-                    .expect("This is always a collection (sampler contract)");
-                insert_data(datasource, n.to_string().clone(), collection)?;
+        SamplerOutput::Namespace(namespace) => {
+            for (name, collection) in namespace {
+                insert_data(datasource, name, &collection)?;
             };
             Ok(())
         }
-        _ => bail!(
-            "The sampler will never generate a value which is not an array or object (sampler contract)"
-        ),
     }
 }
 
diff --git a/synth/src/cli/mongo.rs b/synth/src/cli/mongo.rs
index fed21cd3..b71e124f 100644
--- a/synth/src/cli/mongo.rs
+++ b/synth/src/cli/mongo.rs
@@ -1,6 +1,6 @@
 use crate::cli::export::{ExportParams, ExportStrategy};
 use crate::cli::import::ImportStrategy;
-use crate::sampler::Sampler;
+use crate::sampler::{Sampler, SamplerOutput};
 use anyhow::Result;
 use chrono::{DateTime, Utc};
 use mongodb::bson::Bson;
@@ -170,28 +170,19 @@ impl ExportStrategy for MongoExportStrategy {
     fn export(self, params: ExportParams) -> Result<()> {
         let mut client = Client::with_uri_str(&self.uri)?;
         let sampler = Sampler::try_from(&params.namespace)?;
-        let values =
+        let output =
             sampler.sample_seeded(params.collection_name.clone(), params.target, params.seed)?;
 
-        match values {
-            Value::Array(collection_json) => {
-                self.insert_data(params.collection_name.unwrap().to_string(), &collection_json, &mut client)
+        match output {
+            SamplerOutput::Collection(values) => {
+                self.insert_data(params.collection_name.unwrap().to_string(), &values, &mut client)
             }
-            Value::Object(namespace_json) => {
-                for (collection_name, collection_json) in namespace_json {
-                    self.insert_data(
-                        collection_name,
-                        collection_json
-                            .as_array()
-                            .expect("This is always a collection (sampler contract)"),
-                        &mut client,
-                    )?;
+            SamplerOutput::Namespace(namespace) => {
+                for (name, values) in namespace {
+                    self.insert_data(name, &values, &mut client)?;
                 }
                 Ok(())
             }
-            _ => unreachable!(
-                "The sampler will never generate a value which is not an array or object (sampler contract)"
-            ),
         }
     }
 }
diff --git a/synth/src/cli/stdf.rs b/synth/src/cli/stdf.rs
index 19aeaffd..2f7605a9 100644
--- a/synth/src/cli/stdf.rs
+++ b/synth/src/cli/stdf.rs
@@ -1,6 +1,5 @@
 use crate::cli::export::{ExportParams, ExportStrategy};
 use crate::cli::import::ImportStrategy;
-use crate::cli::json::synth_val_to_json;
 use crate::sampler::Sampler;
 use anyhow::Result;
 use serde_json::Value;
@@ -23,8 +22,8 @@ pub struct StdoutExportStrategy {}
 impl ExportStrategy for StdoutExportStrategy {
     fn export(self, params: ExportParams) -> Result<()> {
         let generator = Sampler::try_from(&params.namespace)?;
-        let values = generator.sample_seeded(params.collection_name, params.target, params.seed)?;
-        println!("{}", synth_val_to_json(values));
+        let output = generator.sample_seeded(params.collection_name, params.target, params.seed)?;
+        println!("{}", output.into_json());
         Ok(())
     }
 }
diff --git a/synth/src/sampler.rs b/synth/src/sampler.rs
index 56e05d74..11ee9e3a 100644
--- a/synth/src/sampler.rs
+++ b/synth/src/sampler.rs
@@ -2,14 +2,36 @@ use anyhow::Result;
 use indicatif::{ProgressBar, ProgressStyle};
 use rand::SeedableRng;
 use synth_core::{Graph, Name, Namespace, Value};
+use synth_core::graph::json::synth_val_to_json;
 use synth_gen::prelude::*;
-use std::collections::{btree_map::Entry, BTreeMap};
+use std::collections::BTreeMap;
 use std::convert::TryFrom;
 
 pub(crate) struct Sampler {
     graph: Graph,
 }
 
+pub(crate) enum SamplerOutput {
+    Namespace(Vec<(String, Vec<Value>)>),
+    Collection(Vec<Value>)
+}
+
+impl SamplerOutput {
+    pub(crate) fn into_json(self) -> serde_json::Value {
+        let as_synth = match self {
+            Self::Namespace(key_values) => {
+                let object = key_values
+                    .into_iter()
+                    .map(|(key, values)| (key, Value::Array(values)))
+                    .collect();
+                Value::Object(object)
+            }
+            Self::Collection(values) => Value::Array(values)
+        };
+        synth_val_to_json(as_synth)
+    }
+}
+
 fn sampler_progress_bar(target: u64) -> ProgressBar {
     let bar = ProgressBar::new(target as u64);
     let style = ProgressStyle::default_bar()
@@ -24,11 +46,10 @@ impl Sampler {
         collection_name: Option<Name>,
         target: usize,
         seed: u64,
-    ) -> Result<Value> {
+    ) -> Result<SamplerOutput> {
         let rng = rand::rngs::StdRng::seed_from_u64(seed);
-        let model = self.graph.aggregate();
         let sample_strategy = SampleStrategy::new(collection_name, target);
-        sample_strategy.sample(model, rng)
+        sample_strategy.sample(self.graph, rng)
     }
 }
 
@@ -59,10 +80,10 @@ impl SampleStrategy {
         }
     }
 
-    fn sample<R: Rng>(&self, model: Aggregate<Graph>, rng: R) -> Result<Value> {
+    fn sample<R: Rng>(self, model: Graph, rng: R) -> Result<SamplerOutput> {
         match self {
-            SampleStrategy::Namespace(nss) => nss.sample(model, rng),
-            SampleStrategy::Collection(css) => css.sample(model, rng)
+            SampleStrategy::Namespace(nss) => Ok(SamplerOutput::Namespace(nss.sample(model, rng)?)),
+            SampleStrategy::Collection(css) => Ok(SamplerOutput::Collection(css.sample(model, rng)?))
         }
     }
 }
@@ -72,34 +93,30 @@ struct NamespaceSampleStrategy {
 }
 
 impl NamespaceSampleStrategy {
-    fn sample<R: Rng>(&self, mut model: Aggregate<Graph>, mut rng: R) -> Result<Value> {
+    fn sample<R: Rng>(self, model: Graph, mut rng: R) -> Result<Vec<(String, Vec<Value>)>> {
         let mut generated = 0;
-        let mut out = BTreeMap::new();
+        let mut out = BTreeMap::<String, Vec<Value>>::new();
         let progress_bar = sampler_progress_bar(self.target as u64);
 
+        let ordered: Vec<_> = model
+            .iter_ordered()
+            .map(|iter| iter.map(|s| s.to_string()).collect())
+            .unwrap_or_else(Vec::new);
+
+        let mut model = model.aggregate();
+
         while generated < self.target {
+	    // We populate `out` by walking through the collections in the generated
+	    // namespace. We also keep track of the number of `Values` generated
+	    // for the progress bar.
             let next = model.complete(&mut rng)?;
-            // Here we are building a BTreeMap.
-            // Keys are the name of the collection and values are vectors of type synth_core::Value.
-            // If the key is absent, we insert the first vec sampled, otherwise we extend the existing Vec.
-            // In the future this should be replaced by a Sample/Samples struct which encapsulates this complexity.
             as_object(next)?
                 .into_iter()
                 .try_for_each(|(collection, value)| {
                     as_array(&collection, value)
                         .map(|vec| {
                             generated += vec.len();
-                            match out.entry(collection) {
-                                Entry::Vacant(e) => {
-                                    e.insert(Value::Array(vec));
-                                }
-                                Entry::Occupied(mut o) => {
-                                    match o.get_mut() {
-                                        Value::Array(arr) => arr.extend(vec),
-                                        _ => unreachable!("This is never not an array.")
-                                    }
-                                }
-                            }
+                            out.entry(collection).or_default().extend(vec);
                         })
                 })?;
             progress_bar.set_position(generated as u64);
@@ -107,7 +124,16 @@ impl NamespaceSampleStrategy {
 
         progress_bar.finish_and_clear();
 
-        Ok(Value::Object(out))
+        let mut ordered_out = Vec::new();
+
+        for name in ordered {
+            let value = out.remove(&name).unwrap();
+            ordered_out.push((name, value));
+        }
+
+        ordered_out.extend(out.into_iter());
+
+        Ok(ordered_out)
     }
 }
 
@@ -117,11 +143,13 @@ struct CollectionSampleStrategy {
 }
 
 impl CollectionSampleStrategy {
-    fn sample<R: Rng>(&self, mut model: Aggregate<Graph>, mut rng: R) -> Result<Value> {
+    fn sample<R: Rng>(self, model: Graph, mut rng: R) -> Result<Vec<Value>> {
         let mut out = vec![];
         let mut generated = 0;
         let progress_bar = sampler_progress_bar(self.target as u64);
 
+        let mut model = model.aggregate();
+
         while generated < self.target {
             let next = model.complete(&mut rng)?;
             let collection_value = as_object(next)?.remove(self.name.as_ref()).ok_or_else(|| {
@@ -139,7 +167,7 @@ impl CollectionSampleStrategy {
 
         progress_bar.finish_and_clear();
 
-        Ok(Value::Array(out))
+        Ok(out)
     }
 }
 


Test patch: