Index: doc/proposals/modules-alvin/examples/graph/0_initial/graph.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/0_initial/graph.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/0_initial/graph.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,43 @@
+module;
+
+import graph/node;
+import graph/edge;
+
+import stdlib;
+
+export struct Graph {
+    struct Node *nodes;
+    struct Edge *edges;
+    int num_nodes;
+    int num_edges;
+};
+
+export struct Graph create_rand_graph(int num_nodes, int num_edges) {
+    struct Graph g;
+    g.num_nodes = num_nodes;
+    g.num_edges = num_edges;
+    g.nodes = (struct Node *) calloc(num_nodes, sizeof(struct Node));
+    g.edges = (struct Edge *) calloc(num_edges, * sizeof(struct Edge));
+    for (int i=0; i<num_edges; ++i) {
+        struct Node *first = grab_random_node(&g), *second = grab_random_node(&g);
+        g.edges[i] = create_edge(first, second);
+        add_edge(first, &g.edges[i]);
+        add_edge(second, &g.edges[i]);
+    }
+    return g;
+}
+
+export struct Node *grab_random_node(struct Graph *g) {
+    return &g->nodes[rand() % g->num_nodes];
+}
+
+const int max_steps_to_walk = 1000;
+export int path_found(struct Node *first, struct Node *second) {
+    return random_search(first, second, max_steps_to_walk);
+}
+
+export int destroy_graph(struct Graph *g) {
+    free(g->nodes);
+    free(g->edges);
+    return 0;
+}
Index: doc/proposals/modules-alvin/examples/graph/0_initial/graph/edge.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/0_initial/graph/edge.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/0_initial/graph/edge.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,17 @@
+module;
+
+import node;
+
+export struct Edge {
+    struct Node *nodes[2];
+    struct Other o;
+};
+
+struct Other {};
+
+export struct Edge create_edge(struct Node *first, struct Node *second) {
+    struct Edge e;
+    e.nodes[0] = first;
+    e.nodes[1] = second;
+    return e;
+}
Index: doc/proposals/modules-alvin/examples/graph/0_initial/graph/edge_picker.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/0_initial/graph/edge_picker.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/0_initial/graph/edge_picker.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,18 @@
+module;
+
+import edge;
+import node;
+
+import stdlib;
+
+struct Controller {};
+
+export struct Controller get_controller() {
+    return (struct Controller){};
+}
+
+export struct Node *pick_next(struct Controller *c, struct Node *n) {
+    if (n->num_edges == 0) return NULL;
+    struct Edge *e = n->edges[rand() % n->num_edges];
+    return e->nodes[0] == n ? e->nodes[1] : e->nodes[0];
+}
Index: doc/proposals/modules-alvin/examples/graph/0_initial/graph/node.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/0_initial/graph/node.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/0_initial/graph/node.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,39 @@
+module;
+
+import edge;
+import edge_picker;
+
+import stdlib;
+
+export struct Node {
+    int num_edges;
+    struct Edge *edges[max_edges_per_node];
+    struct Other o;
+}
+const int max_edges_per_node = 100;  // don't want to set up a dynamic array
+
+struct Other {};
+
+export int add_edge(struct Node *n, struct Edge *e) {
+    if (n->num_edges >= max_edges_per_node) exit(2);
+    n->edges[n->num_edges++] = e;
+    return 1;
+}
+
+export int random_search(struct Node *start, struct Node *end, int steps_left) {
+    while (steps_left > 0) {
+        int result = random_search$$mangle(start, end, &steps_left);
+        if (result != 0) return result;
+    }
+    return 0;
+}
+
+const int continue_rate = 2;
+int random_search$$mangle(struct Node *start, struct Node *end, int *steps_left) {
+    if (start == end) return 1;
+    (*steps_left)--;
+    if (rand() % continue_rate == 0) return 0;
+    struct Controller c = get_controller();
+    struct Node *n = pick_next(&c, start);
+    return random_search$$mangle(n, end, steps_left);
+}
Index: doc/proposals/modules-alvin/examples/graph/0_initial/main.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/0_initial/main.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/0_initial/main.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,83 @@
+// Graph searching algorithm testing script
+
+import graph;
+
+import stdio;
+import stdlib;
+import unistd;
+
+void print_usage() {
+    printf("Usage: program_name [-n num_iter] [-s seed] [-N num_nodes] [-E num_edges] [-c num_checks] [-h]\n");
+    printf("Options:\n");
+    printf("  -n num_iter   Number of graphs to run on\n");
+    printf("  -s seed       Seed for random number generator\n");
+    printf("  -N num_nodes  Number of nodes in generated graph\n");
+    printf("  -E num_edges  Number of edges in generated graph\n");
+    printf("  -c num_checks Number of times to check graph for paths\n");
+    printf("  -h            Display this help message\n");
+}
+
+struct Arg {
+    int num_iter, seed, num_nodes, num_edges, num_checks;
+};
+
+struct Arg process_args(int argc, char *argv[]) {
+    int opt;
+    struct Arg args;
+    args.num_iter = 10;
+    args.seed = 0;
+    args.num_nodes = 100;
+    args.num_edges = 100;
+    args.num_checks = 10;
+
+    // Parse command line options
+    while ((opt = getopt(argc, argv, "n:s:N:E:c:h")) != -1) {
+        switch (opt) {
+            case 'n':
+                args.num_iter = atoi(optarg);
+                break;
+            case 's':
+                args.seed = atoi(optarg);
+                break;
+            case 'N':
+                args.num_nodes = atoi(optarg);
+                break;
+            case 'E':
+                args.num_edges = atoi(optarg);
+                break;
+            case 'c':
+                args.num_checks = atoi(optarg);
+                break;
+            case 'h':
+                print_usage(); // Print usage information
+                exit(0);
+            case '?':
+                // Handle unknown options
+                fprintf(stderr, "Unknown option: -%c\n", optopt);
+                print_usage();
+                exit(1);
+            default:
+                print_usage();
+                exit(1);
+        }
+    }
+    return args;
+}
+
+int main(int argc, char *argv[]) {
+    struct Arg args = process_args(argc, argv);
+    int total_paths = 0;
+    srand(args.seed);
+    for (int i=0; i<args.num_iter; ++i) {
+        struct Graph g = create_rand_graph(args.num_nodes, args.num_edges);
+        int paths_found = 0;
+        for (int j=0; j<args.num_checks; ++j) {
+            struct Node *n1 = grab_random_node(&g);
+            struct Node *n2 = grab_random_node(&g);
+            paths_found += path_found(n1, n2);  // it's technically returning a bool
+        }
+        destroy_graph(&g);
+        printf("Graph %d: %d paths found over %d checks.\n", i, paths_found, args.num_checks);
+    }
+    printf("Summary: %d graphs * %d checks = %d total checks performed, %d paths found.\n", args.num_iter, args.num_checks, args.num_iter * args.num_checks, total_paths);
+}
Index: doc/proposals/modules-alvin/examples/graph/1_size_analysis/size_analysis.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/1_size_analysis/size_analysis.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/1_size_analysis/size_analysis.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,88 @@
+// First, have a graph of file import dependencies
+// graph/edge_picker.c : graph/node.c graph/edge.c
+// graph/node.c : graph/edge_picker.c graph/edge.c
+// graph/edge.c : graph/node.c
+// graph.c : graph/node.c graph/edge.c
+// main.c : graph.c
+
+// Second, collect all symbols related to types in the modules
+// // graph/edge_picker.c
+// struct Controller {};
+// // graph/node.c
+// struct Node {
+//     int num_edges;
+//     struct Edge *edges[max_edges_per_node];
+//     struct Other o;
+// };
+// const int max_edges_per_node = 100;
+// struct Other {};
+// // graph/edge.c
+// struct Edge {
+//     struct Node *nodes[2];
+//     struct Other o;
+// };
+// struct Other {};
+// // graph.c
+// struct Graph {
+//     struct Node *nodes;
+//     struct Edge *edges;
+//     int num_nodes;
+//     int num_edges;
+// };
+// // main.c
+// struct Arg {
+//     int num_iter, seed, num_nodes, num_edges, num_checks;
+// };
+
+// Third, analyze imports to add namespaces and produce an ordering
+// graph/edge_picker.c
+struct graph$edge_picker$$Controller {};
+// graph/node.c
+const int graph$node$$max_edges_per_node = 100;
+struct graph$node$$Other {};
+struct graph$node$$Node {
+    int num_edges;
+    struct graph$edge$$Edge *edges[graph$node$$max_edges_per_node];
+    struct graph$node$$Other o;
+};
+// graph/edge.c
+struct graph$edge$$Other {};
+struct graph$edge$$Edge {
+    struct graph$node$$Node *nodes[2];
+    struct graph$edge$$Other o;
+};
+// graph.c
+struct graph$$Graph {
+    struct graph$node$$Node *nodes;
+    struct graph$node$$Edge *edges;
+    int num_nodes;
+    int num_edges;
+};
+// main.c
+struct Arg {
+    int num_iter, seed, num_nodes, num_edges, num_checks;
+};
+
+// Fourth, print out size/alignment information
+#include <stdio.h>
+#define PRINT_TYPE_INFO(T) \
+    printf("%-40s size = %4zu   align = %4zu\n", \
+        #T, (size_t)sizeof(T), (size_t)_Alignof(T))
+int main() {
+    PRINT_TYPE_INFO(struct graph$edge_picker$$Controller);
+    PRINT_TYPE_INFO(struct graph$node$$Other);
+    PRINT_TYPE_INFO(struct graph$node$$Node);
+    PRINT_TYPE_INFO(struct graph$edge$$Other);
+    PRINT_TYPE_INFO(struct graph$edge$$Edge);
+    PRINT_TYPE_INFO(struct graph$$Graph);
+    PRINT_TYPE_INFO(struct Arg);
+}
+
+// Prints:
+// struct graph$edge_picker$$Controller     size =    0   align =    1
+// struct graph$node$$Other                 size =    0   align =    1
+// struct graph$node$$Node                  size =  808   align =    8
+// struct graph$edge$$Other                 size =    0   align =    1
+// struct graph$edge$$Edge                  size =   16   align =    8
+// struct graph$$Graph                      size =   24   align =    8
+// struct Arg                               size =   20   align =    4
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/graph.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/graph.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/graph.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,43 @@
+module;
+
+import graph/node;
+import graph/edge;
+
+import stdlib;
+
+export struct Graph {
+    struct Node *nodes;
+    struct Edge *edges;
+    int num_nodes;
+    int num_edges;
+};
+
+export struct Graph create_rand_graph(int num_nodes, int num_edges) {
+    struct Graph g;
+    g.num_nodes = num_nodes;
+    g.num_edges = num_edges;
+    g.nodes = (struct Node *) calloc(num_nodes, sizeof(struct Node));
+    g.edges = (struct Edge *) calloc(num_edges, * sizeof(struct Edge));
+    for (int i=0; i<num_edges; ++i) {
+        struct Node *first = grab_random_node(&g), *second = grab_random_node(&g);
+        g.edges[i] = create_edge(first, second);
+        add_edge(first, &g.edges[i]);
+        add_edge(second, &g.edges[i]);
+    }
+    return g;
+}
+
+export struct Node *grab_random_node(struct Graph *g) {
+    return &g->nodes[rand() % g->num_nodes];
+}
+
+const int max_steps_to_walk = 1000;
+export int path_found(struct Node *first, struct Node *second) {
+    return random_search(first, second, max_steps_to_walk);
+}
+
+export int destroy_graph(struct Graph *g) {
+    free(g->nodes);
+    free(g->edges);
+    return 0;
+}
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,17 @@
+module;
+
+import node;
+
+export struct Edge {
+    struct Node *nodes[2];
+    struct Other o;
+};
+
+struct Other {};
+
+export struct Edge create_edge(struct Node *first, struct Node *second) {
+    struct Edge e;
+    e.nodes[0] = first;
+    e.nodes[1] = second;
+    return e;
+}
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,9 @@
+#pragma once
+
+// [[size 16, align 8]]
+struct graph$edge$$Edge$$shell {
+    double contents[2];  // just to fill space, not used
+};
+
+// [[size 0, align 1]]
+struct graph$edge$$Other$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge_picker.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge_picker.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge_picker.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,18 @@
+module;
+
+import edge;
+import node;
+
+import stdlib;
+
+struct Controller {};
+
+export struct Controller get_controller() {
+    return (struct Controller){};
+}
+
+export struct Node *pick_next(struct Controller *c, struct Node *n) {
+    if (n->num_edges == 0) return NULL;
+    struct Edge *e = n->edges[rand() % n->num_edges];
+    return e->nodes[0] == n ? e->nodes[1] : e->nodes[0];
+}
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge_picker__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge_picker__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/graph/edge_picker__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,4 @@
+#pragma once
+
+// [[size 0, align 1]]
+struct graph$edge_picker$$Controller$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/graph/node.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/graph/node.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/graph/node.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,39 @@
+module;
+
+import edge;
+import edge_picker;
+
+import stdlib;
+
+export struct Node {
+    int num_edges;
+    struct Edge *edges[max_edges_per_node];
+    struct Other o;
+}
+const int max_edges_per_node = 100;  // don't want to set up a dynamic array
+
+struct Other {};
+
+export int add_edge(struct Node *n, struct Edge *e) {
+    if (n->num_edges >= max_edges_per_node) exit(2);
+    n->edges[n->num_edges++] = e;
+    return 1;
+}
+
+export int random_search(struct Node *start, struct Node *end, int steps_left) {
+    while (steps_left > 0) {
+        int result = random_search$$mangle(start, end, &steps_left);
+        if (result != 0) return result;
+    }
+    return 0;
+}
+
+const int continue_rate = 2;
+int random_search$$mangle(struct Node *start, struct Node *end, int *steps_left) {
+    if (start == end) return 1;
+    (*steps_left)--;
+    if (rand() % continue_rate == 0) return 0;
+    struct Controller c = get_controller();
+    struct Node *n = pick_next(&c, start);
+    return random_search$$mangle(n, end, steps_left);
+}
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/graph/node__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/graph/node__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/graph/node__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,9 @@
+#pragma once
+
+// [[size 808, align 8]]
+struct graph$node$$Node$$shell {
+    double contents[101];  // just to fill space, not used
+};
+
+// [[size 0, align 1]]
+struct graph$node$$Other$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/graph__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/graph__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/graph__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,6 @@
+#pragma once
+
+// [[size 24, align 8]]
+struct graph$$Graph$$shell {
+    double contents[3];  // just to fill space, not used
+};
Index: doc/proposals/modules-alvin/examples/graph/2_tshell/main.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/2_tshell/main.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/2_tshell/main.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,83 @@
+// Graph searching algorithm testing script
+
+import graph;
+
+import stdio;
+import stdlib;
+import unistd;
+
+void print_usage() {
+    printf("Usage: program_name [-n num_iter] [-s seed] [-N num_nodes] [-E num_edges] [-c num_checks] [-h]\n");
+    printf("Options:\n");
+    printf("  -n num_iter   Number of graphs to run on\n");
+    printf("  -s seed       Seed for random number generator\n");
+    printf("  -N num_nodes  Number of nodes in generated graph\n");
+    printf("  -E num_edges  Number of edges in generated graph\n");
+    printf("  -c num_checks Number of times to check graph for paths\n");
+    printf("  -h            Display this help message\n");
+}
+
+struct Arg {
+    int num_iter, seed, num_nodes, num_edges, num_checks;
+};
+
+struct Arg process_args(int argc, char *argv[]) {
+    int opt;
+    struct Arg args;
+    args.num_iter = 10;
+    args.seed = 0;
+    args.num_nodes = 100;
+    args.num_edges = 100;
+    args.num_checks = 10;
+
+    // Parse command line options
+    while ((opt = getopt(argc, argv, "n:s:N:E:c:h")) != -1) {
+        switch (opt) {
+            case 'n':
+                args.num_iter = atoi(optarg);
+                break;
+            case 's':
+                args.seed = atoi(optarg);
+                break;
+            case 'N':
+                args.num_nodes = atoi(optarg);
+                break;
+            case 'E':
+                args.num_edges = atoi(optarg);
+                break;
+            case 'c':
+                args.num_checks = atoi(optarg);
+                break;
+            case 'h':
+                print_usage(); // Print usage information
+                exit(0);
+            case '?':
+                // Handle unknown options
+                fprintf(stderr, "Unknown option: -%c\n", optopt);
+                print_usage();
+                exit(1);
+            default:
+                print_usage();
+                exit(1);
+        }
+    }
+    return args;
+}
+
+int main(int argc, char *argv[]) {
+    struct Arg args = process_args(argc, argv);
+    int total_paths = 0;
+    srand(args.seed);
+    for (int i=0; i<args.num_iter; ++i) {
+        struct Graph g = create_rand_graph(args.num_nodes, args.num_edges);
+        int paths_found = 0;
+        for (int j=0; j<args.num_checks; ++j) {
+            struct Node *n1 = grab_random_node(&g);
+            struct Node *n2 = grab_random_node(&g);
+            paths_found += path_found(n1, n2);  // it's technically returning a bool
+        }
+        destroy_graph(&g);
+        printf("Graph %d: %d paths found over %d checks.\n", i, paths_found, args.num_checks);
+    }
+    printf("Summary: %d graphs * %d checks = %d total checks performed, %d paths found.\n", args.num_iter, args.num_checks, args.num_iter * args.num_checks, total_paths);
+}
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,43 @@
+module;
+
+import graph/node;
+import graph/edge;
+
+import stdlib;
+
+export struct Graph {
+    struct Node *nodes;
+    struct Edge *edges;
+    int num_nodes;
+    int num_edges;
+};
+
+export struct Graph create_rand_graph(int num_nodes, int num_edges) {
+    struct Graph g;
+    g.num_nodes = num_nodes;
+    g.num_edges = num_edges;
+    g.nodes = (struct Node *) calloc(num_nodes, sizeof(struct Node));
+    g.edges = (struct Edge *) calloc(num_edges, * sizeof(struct Edge));
+    for (int i=0; i<num_edges; ++i) {
+        struct Node *first = grab_random_node(&g), *second = grab_random_node(&g);
+        g.edges[i] = create_edge(first, second);
+        add_edge(first, &g.edges[i]);
+        add_edge(second, &g.edges[i]);
+    }
+    return g;
+}
+
+export struct Node *grab_random_node(struct Graph *g) {
+    return &g->nodes[rand() % g->num_nodes];
+}
+
+const int max_steps_to_walk = 1000;
+export int path_found(struct Node *first, struct Node *second) {
+    return random_search(first, second, max_steps_to_walk);
+}
+
+export int destroy_graph(struct Graph *g) {
+    free(g->nodes);
+    free(g->edges);
+    return 0;
+}
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/edge.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/edge.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/edge.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,17 @@
+module;
+
+import node;
+
+export struct Edge {
+    struct Node *nodes[2];
+    struct Other o;
+};
+
+struct Other {};
+
+export struct Edge create_edge(struct Node *first, struct Node *second) {
+    struct Edge e;
+    e.nodes[0] = first;
+    e.nodes[1] = second;
+    return e;
+}
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/edge__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/edge__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/edge__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "edge__tshell.h"
+
+#include "node__tshell.h"
+
+struct graph$edge$$Edge {
+    struct graph$node$$Node$$shell *nodes[2];
+    struct graph$edge$$Other$$shell o;
+};
+
+struct graph$edge$$Edge$$shell graph$edge$$create_edge(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second);
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/edge__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/edge__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/edge__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,9 @@
+#pragma once
+
+// [[size 16, align 8]]
+struct graph$edge$$Edge$$shell {
+    double contents[2];  // just to fill space, not used
+};
+
+// [[size 0, align 1]]
+struct graph$edge$$Other$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,18 @@
+module;
+
+import edge;
+import node;
+
+import stdlib;
+
+struct Controller {};
+
+export struct Controller get_controller() {
+    return (struct Controller){};
+}
+
+export struct Node *pick_next(struct Controller *c, struct Node *n) {
+    if (n->num_edges == 0) return NULL;
+    struct Edge *e = n->edges[rand() % n->num_edges];
+    return e->nodes[0] == n ? e->nodes[1] : e->nodes[0];
+}
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "edge_picker__tshell.h"
+
+#include "edge__tshell.h"
+#include "node__tshell.h"
+
+#include <stdlib__tshell.h>
+
+struct graph$edge_picker$$Controller$$shell graph$edge_picker$$get_controller();
+
+struct graph$node$$Node$$shell *graph$edge_picker$$pick_next(struct graph$edge_picker$$Controller$$shell *c, struct graph$node$$Node$$shell *n);
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/edge_picker__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,4 @@
+#pragma once
+
+// [[size 0, align 1]]
+struct graph$edge_picker$$Controller$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/node.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/node.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/node.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,39 @@
+module;
+
+import edge;
+import edge_picker;
+
+import stdlib;
+
+export struct Node {
+    int num_edges;
+    struct Edge *edges[max_edges_per_node];
+    struct Other o;
+}
+const int max_edges_per_node = 100;  // don't want to set up a dynamic array
+
+struct Other {};
+
+export int add_edge(struct Node *n, struct Edge *e) {
+    if (n->num_edges >= max_edges_per_node) exit(2);
+    n->edges[n->num_edges++] = e;
+    return 1;
+}
+
+export int random_search(struct Node *start, struct Node *end, int steps_left) {
+    while (steps_left > 0) {
+        int result = random_search$$mangle(start, end, &steps_left);
+        if (result != 0) return result;
+    }
+    return 0;
+}
+
+const int continue_rate = 2;
+int random_search$$mangle(struct Node *start, struct Node *end, int *steps_left) {
+    if (start == end) return 1;
+    (*steps_left)--;
+    if (rand() % continue_rate == 0) return 0;
+    struct Controller c = get_controller();
+    struct Node *n = pick_next(&c, start);
+    return random_search$$mangle(n, end, steps_left);
+}
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/node__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/node__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/node__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "node__tshell.h"
+
+#include "edge__tshell.h"
+#include "edge_picker__tshell.h"
+
+#include <stdlib__tshell.h>
+
+// Note: constant max_edges_per_node expanded here
+struct graph$node$$Node {
+    int num_edges;
+    struct graph$edge$$Edge$$shell *edges[100];
+    struct graph$node$$Other$$shell o;
+};
+
+int graph$node$$add_edge(struct graph$node$$Node$$shell *n, struct graph$edge$$Edge$$shell *e);
+
+int graph$node$$random_search(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int steps_left);
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph/node__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph/node__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph/node__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,9 @@
+#pragma once
+
+// [[size 808, align 8]]
+struct graph$node$$Node$$shell {
+    double contents[101];  // just to fill space, not used
+};
+
+// [[size 0, align 1]]
+struct graph$node$$Other$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "graph__tshell.h"
+
+#include "graph/node__tshell.h"
+#include "graph/edge__tshell.h"
+
+#include <stdlib__tshell.h>
+
+struct graph$$Graph {
+    struct graph$node$$Node$$shell *nodes;
+    struct graph$edge$$Edge$$shell *edges;
+    int num_nodes;
+    int num_edges;
+};
+
+struct graph$$Graph$$shell graph$$create_rand_graph(int num_nodes, int num_edges);
+
+struct graph$node$$Node$$shell *graph$$grab_random_node(struct graph$$Graph$$shell *g);
+
+int graph$$path_found(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second);
+
+int graph$$destroy_graph(struct graph$$Graph$$shell *g);
Index: doc/proposals/modules-alvin/examples/graph/3_export/graph__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/graph__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/graph__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,6 @@
+#pragma once
+
+// [[size 24, align 8]]
+struct graph$$Graph$$shell {
+    double contents[3];  // just to fill space, not used
+};
Index: doc/proposals/modules-alvin/examples/graph/3_export/main.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/3_export/main.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/3_export/main.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,83 @@
+// Graph searching algorithm testing script
+
+import graph;
+
+import stdio;
+import stdlib;
+import unistd;
+
+void print_usage() {
+    printf("Usage: program_name [-n num_iter] [-s seed] [-N num_nodes] [-E num_edges] [-c num_checks] [-h]\n");
+    printf("Options:\n");
+    printf("  -n num_iter   Number of graphs to run on\n");
+    printf("  -s seed       Seed for random number generator\n");
+    printf("  -N num_nodes  Number of nodes in generated graph\n");
+    printf("  -E num_edges  Number of edges in generated graph\n");
+    printf("  -c num_checks Number of times to check graph for paths\n");
+    printf("  -h            Display this help message\n");
+}
+
+struct Arg {
+    int num_iter, seed, num_nodes, num_edges, num_checks;
+};
+
+struct Arg process_args(int argc, char *argv[]) {
+    int opt;
+    struct Arg args;
+    args.num_iter = 10;
+    args.seed = 0;
+    args.num_nodes = 100;
+    args.num_edges = 100;
+    args.num_checks = 10;
+
+    // Parse command line options
+    while ((opt = getopt(argc, argv, "n:s:N:E:c:h")) != -1) {
+        switch (opt) {
+            case 'n':
+                args.num_iter = atoi(optarg);
+                break;
+            case 's':
+                args.seed = atoi(optarg);
+                break;
+            case 'N':
+                args.num_nodes = atoi(optarg);
+                break;
+            case 'E':
+                args.num_edges = atoi(optarg);
+                break;
+            case 'c':
+                args.num_checks = atoi(optarg);
+                break;
+            case 'h':
+                print_usage(); // Print usage information
+                exit(0);
+            case '?':
+                // Handle unknown options
+                fprintf(stderr, "Unknown option: -%c\n", optopt);
+                print_usage();
+                exit(1);
+            default:
+                print_usage();
+                exit(1);
+        }
+    }
+    return args;
+}
+
+int main(int argc, char *argv[]) {
+    struct Arg args = process_args(argc, argv);
+    int total_paths = 0;
+    srand(args.seed);
+    for (int i=0; i<args.num_iter; ++i) {
+        struct Graph g = create_rand_graph(args.num_nodes, args.num_edges);
+        int paths_found = 0;
+        for (int j=0; j<args.num_checks; ++j) {
+            struct Node *n1 = grab_random_node(&g);
+            struct Node *n2 = grab_random_node(&g);
+            paths_found += path_found(n1, n2);  // it's technically returning a bool
+        }
+        destroy_graph(&g);
+        printf("Graph %d: %d paths found over %d checks.\n", i, paths_found, args.num_checks);
+    }
+    printf("Summary: %d graphs * %d checks = %d total checks performed, %d paths found.\n", args.num_iter, args.num_checks, args.num_iter * args.num_checks, total_paths);
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,43 @@
+module;
+
+import graph/node;
+import graph/edge;
+
+import stdlib;
+
+export struct Graph {
+    struct Node *nodes;
+    struct Edge *edges;
+    int num_nodes;
+    int num_edges;
+};
+
+export struct Graph create_rand_graph(int num_nodes, int num_edges) {
+    struct Graph g;
+    g.num_nodes = num_nodes;
+    g.num_edges = num_edges;
+    g.nodes = (struct Node *) calloc(num_nodes, sizeof(struct Node));
+    g.edges = (struct Edge *) calloc(num_edges, * sizeof(struct Edge));
+    for (int i=0; i<num_edges; ++i) {
+        struct Node *first = grab_random_node(&g), *second = grab_random_node(&g);
+        g.edges[i] = create_edge(first, second);
+        add_edge(first, &g.edges[i]);
+        add_edge(second, &g.edges[i]);
+    }
+    return g;
+}
+
+export struct Node *grab_random_node(struct Graph *g) {
+    return &g->nodes[rand() % g->num_nodes];
+}
+
+const int max_steps_to_walk = 1000;
+export int path_found(struct Node *first, struct Node *second) {
+    return random_search(first, second, max_steps_to_walk);
+}
+
+export int destroy_graph(struct Graph *g) {
+    free(g->nodes);
+    free(g->edges);
+    return 0;
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,17 @@
+module;
+
+import node;
+
+export struct Edge {
+    struct Node *nodes[2];
+    struct Other o;
+};
+
+struct Other {};
+
+export struct Edge create_edge(struct Node *first, struct Node *second) {
+    struct Edge e;
+    e.nodes[0] = first;
+    e.nodes[1] = second;
+    return e;
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "edge__tshell.h"
+
+#include "node__tshell.h"
+
+struct graph$edge$$Edge {
+    struct graph$node$$Node$$shell *nodes[2];
+    struct graph$edge$$Other$$shell o;
+};
+
+struct graph$edge$$Edge$$shell graph$edge$$create_edge(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second);
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,12 @@
+#include "edge__export.h"
+
+#include "node__export.h"
+
+struct graph$edge$$Other {};
+
+struct graph$edge$$Edge$$shell graph$edge$$create_edge(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second) {
+    struct graph$edge$$Edge$$shell e;
+    (*(struct graph$edge$$Edge*)&e).nodes[0] = first;
+    (*(struct graph$edge$$Edge*)&e).nodes[1] = second;
+    return e;
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,9 @@
+#pragma once
+
+// [[size 16, align 8]]
+struct graph$edge$$Edge$$shell {
+    double contents[2];  // just to fill space, not used
+};
+
+// [[size 0, align 1]]
+struct graph$edge$$Other$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,18 @@
+module;
+
+import edge;
+import node;
+
+import stdlib;
+
+struct Controller {};
+
+export struct Controller get_controller() {
+    return (struct Controller){};
+}
+
+export struct Node *pick_next(struct Controller *c, struct Node *n) {
+    if (n->num_edges == 0) return NULL;
+    struct Edge *e = n->edges[rand() % n->num_edges];
+    return e->nodes[0] == n ? e->nodes[1] : e->nodes[0];
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "edge_picker__tshell.h"
+
+#include "edge__tshell.h"
+#include "node__tshell.h"
+
+#include <stdlib__tshell.h>
+
+struct graph$edge_picker$$Controller$$shell graph$edge_picker$$get_controller();
+
+struct graph$node$$Node$$shell *graph$edge_picker$$pick_next(struct graph$edge_picker$$Controller$$shell *c, struct graph$node$$Node$$shell *n);
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,18 @@
+#include "edge_picker__export.h"
+
+#include "edge__export.h"
+#include "node__export.h"
+
+#include <stdlib__export.h>
+
+struct graph$edge_picker$$Controller {};
+
+struct graph$edge_picker$$Controller$$shell graph$edge_picker$$get_controller() {
+    return (*(struct graph$edge_picker$$Controller$$shell*)&(struct graph$edge_picker$$Controller){});
+}
+
+struct graph$node$$Node$$shell *graph$edge_picker$$pick_next(struct graph$edge_picker$$Controller$$shell *c, struct graph$node$$Node$$shell *n) {
+    if (((struct graph$node$$Node*)n)->num_edges == 0) return NULL;
+    struct graph$edge$$Edge$$shell *e = ((struct graph$node$$Node*)n)->edges[rand() % ((struct graph$node$$Node*)n)->num_edges];
+    return ((struct graph$node$$Node*)((struct graph$edge$$Edge*)e)->nodes[0]) == ((struct graph$node$$Node*)n) ? ((struct graph$edge$$Edge*)e)->nodes[1] : ((struct graph$edge$$Edge*)e)->nodes[0];
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/edge_picker__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,4 @@
+#pragma once
+
+// [[size 0, align 1]]
+struct graph$edge_picker$$Controller$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/node.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/node.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/node.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,39 @@
+module;
+
+import edge;
+import edge_picker;
+
+import stdlib;
+
+export struct Node {
+    int num_edges;
+    struct Edge *edges[max_edges_per_node];
+    struct Other o;
+}
+const int max_edges_per_node = 100;  // don't want to set up a dynamic array
+
+struct Other {};
+
+export int add_edge(struct Node *n, struct Edge *e) {
+    if (n->num_edges >= max_edges_per_node) exit(2);
+    n->edges[n->num_edges++] = e;
+    return 1;
+}
+
+export int random_search(struct Node *start, struct Node *end, int steps_left) {
+    while (steps_left > 0) {
+        int result = random_search$$mangle(start, end, &steps_left);
+        if (result != 0) return result;
+    }
+    return 0;
+}
+
+const int continue_rate = 2;
+int random_search$$mangle(struct Node *start, struct Node *end, int *steps_left) {
+    if (start == end) return 1;
+    (*steps_left)--;
+    if (rand() % continue_rate == 0) return 0;
+    struct Controller c = get_controller();
+    struct Node *n = pick_next(&c, start);
+    return random_search$$mangle(n, end, steps_left);
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "node__tshell.h"
+
+#include "edge__tshell.h"
+#include "edge_picker__tshell.h"
+
+#include <stdlib__tshell.h>
+
+// Note: constant max_edges_per_node expanded here
+struct graph$node$$Node {
+    int num_edges;
+    struct graph$edge$$Edge$$shell *edges[100];
+    struct graph$node$$Other$$shell o;
+};
+
+int graph$node$$add_edge(struct graph$node$$Node$$shell *n, struct graph$edge$$Edge$$shell *e);
+
+int graph$node$$random_search(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int steps_left);
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,37 @@
+#include "node__export.h"
+
+#include "edge__export.h"
+#include "edge_picker__export.h"
+
+#include <stdlib__export.h>
+
+// move constants to top
+const int graph$node$$max_edges_per_node = 100;
+const int graph$node$$continue_rate = 2;
+
+// also move function declarations (of those not already in `node__export.h`) to top
+int graph$node$$random_search$$mangle(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int *steps_left);
+
+int graph$node$$add_edge(struct graph$node$$Node$$shell *n, struct graph$edge$$Edge$$shell *e) {
+    if (((struct graph$node$$Node*)n)->num_edges >= graph$node$$max_edges_per_node) exit(2);
+    ((struct graph$node$$Node*)n)->edges[((struct graph$node$$Node*)n)->num_edges++] = e;
+    return 1;
+}
+
+int graph$node$$random_search(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int steps_left) {
+    while (steps_left > 0) {
+        int result = graph$node$$random_search$$mangle(start, end, &steps_left);
+        if (result != 0) return result;
+    }
+    return 0;
+}
+
+int graph$node$$random_search$$mangle(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int *steps_left) {
+    if (start == end) return 1;
+    (*steps_left)--;
+    if (rand() % graph$node$$continue_rate == 0) return 0;
+    struct graph$edge_picker$$Controller$$shell c = graph$edge_picker$$get_controller();
+    struct graph$node$$Node$$shell *n = graph$edge_picker$$pick_next(&c, start);
+    if (n == NULL) return 0;
+    return graph$node$$random_search$$mangle(n, end, steps_left);
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph/node__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,9 @@
+#pragma once
+
+// [[size 808, align 8]]
+struct graph$node$$Node$$shell {
+    double contents[101];  // just to fill space, not used
+};
+
+// [[size 0, align 1]]
+struct graph$node$$Other$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "graph__tshell.h"
+
+#include "graph/node__tshell.h"
+#include "graph/edge__tshell.h"
+
+#include <stdlib__tshell.h>
+
+struct graph$$Graph {
+    struct graph$node$$Node$$shell *nodes;
+    struct graph$edge$$Edge$$shell *edges;
+    int num_nodes;
+    int num_edges;
+};
+
+struct graph$$Graph$$shell graph$$create_rand_graph(int num_nodes, int num_edges);
+
+struct graph$node$$Node$$shell *graph$$grab_random_node(struct graph$$Graph$$shell *g);
+
+int graph$$path_found(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second);
+
+int graph$$destroy_graph(struct graph$$Graph$$shell *g);
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,38 @@
+#include "graph__export.h"
+
+#include "graph/node__export.h"
+#include "graph/edge__export.h"
+
+#include <stdlib__export.h>
+
+// move constants to top
+const int graph$$max_steps_to_walk = 1000;
+
+struct graph$$Graph$$shell graph$$create_rand_graph(int num_nodes, int num_edges) {
+    struct graph$$Graph$$shell g;
+    (*(struct graph$$Graph*)&g).num_nodes = num_nodes;
+    (*(struct graph$$Graph*)&g).num_edges = num_edges;
+    (*(struct graph$$Graph*)&g).nodes = (struct graph$node$$Node$$shell *) calloc(num_nodes, sizeof(struct graph$node$$Node$$shell));
+    (*(struct graph$$Graph*)&g).edges = (struct graph$edge$$Edge$$shell *) calloc(num_edges, sizeof(struct graph$edge$$Edge$$shell));
+    for (int i=0; i<num_edges; ++i) {
+        struct graph$node$$Node$$shell *first = graph$$grab_random_node(&g), *second = graph$$grab_random_node(&g);
+        (*(struct graph$$Graph*)&g).edges[i] = graph$edge$$create_edge(first, second);
+        graph$node$$add_edge(first, &(*(struct graph$$Graph*)&g).edges[i]);
+        graph$node$$add_edge(second, &(*(struct graph$$Graph*)&g).edges[i]);
+    }
+    return g;
+}
+
+struct graph$node$$Node$$shell *graph$$grab_random_node(struct graph$$Graph$$shell *g) {
+    return &((struct graph$$Graph*)g)->nodes[rand() % ((struct graph$$Graph*)g)->num_nodes];
+}
+
+int graph$$path_found(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second) {
+    return graph$node$$random_search(first, second, graph$$max_steps_to_walk);
+}
+
+int graph$$destroy_graph(struct graph$$Graph$$shell *g) {
+    free(((struct graph$$Graph*)g)->nodes);
+    free(((struct graph$$Graph*)g)->edges);
+    return 0;
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/graph__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/graph__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/graph__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,6 @@
+#pragma once
+
+// [[size 24, align 8]]
+struct graph$$Graph$$shell {
+    double contents[3];  // just to fill space, not used
+};
Index: doc/proposals/modules-alvin/examples/graph/4_impl/main.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/main.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/main.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,83 @@
+// Graph searching algorithm testing script
+
+import graph;
+
+import stdio;
+import stdlib;
+import unistd;
+
+void print_usage() {
+    printf("Usage: program_name [-n num_iter] [-s seed] [-N num_nodes] [-E num_edges] [-c num_checks] [-h]\n");
+    printf("Options:\n");
+    printf("  -n num_iter   Number of graphs to run on\n");
+    printf("  -s seed       Seed for random number generator\n");
+    printf("  -N num_nodes  Number of nodes in generated graph\n");
+    printf("  -E num_edges  Number of edges in generated graph\n");
+    printf("  -c num_checks Number of times to check graph for paths\n");
+    printf("  -h            Display this help message\n");
+}
+
+struct Arg {
+    int num_iter, seed, num_nodes, num_edges, num_checks;
+};
+
+struct Arg process_args(int argc, char *argv[]) {
+    int opt;
+    struct Arg args;
+    args.num_iter = 10;
+    args.seed = 0;
+    args.num_nodes = 100;
+    args.num_edges = 100;
+    args.num_checks = 10;
+
+    // Parse command line options
+    while ((opt = getopt(argc, argv, "n:s:N:E:c:h")) != -1) {
+        switch (opt) {
+            case 'n':
+                args.num_iter = atoi(optarg);
+                break;
+            case 's':
+                args.seed = atoi(optarg);
+                break;
+            case 'N':
+                args.num_nodes = atoi(optarg);
+                break;
+            case 'E':
+                args.num_edges = atoi(optarg);
+                break;
+            case 'c':
+                args.num_checks = atoi(optarg);
+                break;
+            case 'h':
+                print_usage(); // Print usage information
+                exit(0);
+            case '?':
+                // Handle unknown options
+                fprintf(stderr, "Unknown option: -%c\n", optopt);
+                print_usage();
+                exit(1);
+            default:
+                print_usage();
+                exit(1);
+        }
+    }
+    return args;
+}
+
+int main(int argc, char *argv[]) {
+    struct Arg args = process_args(argc, argv);
+    int total_paths = 0;
+    srand(args.seed);
+    for (int i=0; i<args.num_iter; ++i) {
+        struct Graph g = create_rand_graph(args.num_nodes, args.num_edges);
+        int paths_found = 0;
+        for (int j=0; j<args.num_checks; ++j) {
+            struct Node *n1 = grab_random_node(&g);
+            struct Node *n2 = grab_random_node(&g);
+            paths_found += path_found(n1, n2);  // it's technically returning a bool
+        }
+        destroy_graph(&g);
+        printf("Graph %d: %d paths found over %d checks.\n", i, paths_found, args.num_checks);
+    }
+    printf("Summary: %d graphs * %d checks = %d total checks performed, %d paths found.\n", args.num_iter, args.num_checks, args.num_iter * args.num_checks, total_paths);
+}
Index: doc/proposals/modules-alvin/examples/graph/4_impl/main__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/4_impl/main__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/4_impl/main__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,83 @@
+// Graph searching algorithm testing script
+
+#include "graph__export.h"
+
+#include <stdio__export.h>
+#include <stdlib__export.h>
+#include <unistd__export.h>
+
+void print_usage() {
+    printf("Usage: program_name [-n num_iter] [-s seed] [-N num_nodes] [-E num_edges] [-c num_checks] [-h]\n");
+    printf("Options:\n");
+    printf("  -n num_iter   Number of graphs to run on\n");
+    printf("  -s seed       Seed for random number generator\n");
+    printf("  -N num_nodes  Number of nodes in generated graph\n");
+    printf("  -E num_edges  Number of edges in generated graph\n");
+    printf("  -c num_checks Number of times to check graph for paths\n");
+    printf("  -h            Display this help message\n");
+}
+
+struct Arg {
+    int num_iter, seed, num_nodes, num_edges, num_checks;
+};
+
+struct Arg process_args(int argc, char *argv[]) {
+    int opt;
+    struct Arg args;
+    args.num_iter = 10;
+    args.seed = 0;
+    args.num_nodes = 100;
+    args.num_edges = 100;
+    args.num_checks = 10;
+
+    // Parse command line options
+    while ((opt = getopt(argc, argv, "n:s:N:E:c:h")) != -1) {
+        switch (opt) {
+            case 'n':
+                args.num_iter = atoi(optarg);
+                break;
+            case 's':
+                args.seed = atoi(optarg);
+                break;
+            case 'N':
+                args.num_nodes = atoi(optarg);
+                break;
+            case 'E':
+                args.num_edges = atoi(optarg);
+                break;
+            case 'c':
+                args.num_checks = atoi(optarg);
+                break;
+            case 'h':
+                print_usage(); // Print usage information
+                exit(0);
+            case '?':
+                // Handle unknown options
+                fprintf(stderr, "Unknown option: -%c\n", optopt);
+                print_usage();
+                exit(1);
+            default:
+                print_usage();
+                exit(1);
+        }
+    }
+    return args;
+}
+
+int main(int argc, char *argv[]) {
+    struct Arg args = process_args(argc, argv);
+    int total_paths = 0;
+    srand(args.seed);
+    for (int i=0; i<args.num_iter; ++i) {
+        struct graph$$Graph$$shell g = graph$$create_rand_graph(args.num_nodes, args.num_edges);
+        int paths_found = 0;
+        for (int j=0; j<args.num_checks; ++j) {
+            struct graph$node$$Node$$shell *n1 = graph$$grab_random_node(&g);
+            struct graph$node$$Node$$shell *n2 = graph$$grab_random_node(&g);
+            paths_found += graph$$path_found(n1, n2);  // it's technically returning a bool
+        }
+        graph$$destroy_graph(&g);
+        printf("Graph %d: %d paths found over %d checks.\n", i, paths_found, args.num_checks);
+    }
+    printf("Summary: %d graphs * %d checks = %d total checks performed, %d paths found.\n", args.num_iter, args.num_checks, args.num_iter * args.num_checks, total_paths);
+}
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "edge__tshell.h"
+
+#include "node__tshell.h"
+
+struct graph$edge$$Edge {
+    struct graph$node$$Node$$shell *nodes[2];
+    struct graph$edge$$Other$$shell o;
+};
+
+struct graph$edge$$Edge$$shell graph$edge$$create_edge(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second);
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,12 @@
+#include "edge__export.h"
+
+#include "node__export.h"
+
+struct graph$edge$$Other {};
+
+struct graph$edge$$Edge$$shell graph$edge$$create_edge(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second) {
+    struct graph$edge$$Edge$$shell e;
+    (*(struct graph$edge$$Edge*)&e).nodes[0] = first;
+    (*(struct graph$edge$$Edge*)&e).nodes[1] = second;
+    return e;
+}
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,9 @@
+#pragma once
+
+// [[size 16, align 8]]
+struct graph$edge$$Edge$$shell {
+    double contents[2];  // just to fill space, not used
+};
+
+// [[size 0, align 1]]
+struct graph$edge$$Other$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "edge_picker__tshell.h"
+
+#include "edge__tshell.h"
+#include "node__tshell.h"
+
+struct graph$edge_picker$$Controller$$shell graph$edge_picker$$get_controller();
+
+struct graph$node$$Node$$shell *graph$edge_picker$$pick_next(struct graph$edge_picker$$Controller$$shell *c, struct graph$node$$Node$$shell *n);
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,18 @@
+#include "edge_picker__export.h"
+
+#include "edge__export.h"
+#include "node__export.h"
+
+#include <stdlib.h>
+
+struct graph$edge_picker$$Controller {};
+
+struct graph$edge_picker$$Controller$$shell graph$edge_picker$$get_controller() {
+    return (*(struct graph$edge_picker$$Controller$$shell*)&(struct graph$edge_picker$$Controller){});
+}
+
+struct graph$node$$Node$$shell *graph$edge_picker$$pick_next(struct graph$edge_picker$$Controller$$shell *c, struct graph$node$$Node$$shell *n) {
+    if (((struct graph$node$$Node*)n)->num_edges == 0) return NULL;
+    struct graph$edge$$Edge$$shell *e = ((struct graph$node$$Node*)n)->edges[rand() % ((struct graph$node$$Node*)n)->num_edges];
+    return ((struct graph$node$$Node*)((struct graph$edge$$Edge*)e)->nodes[0]) == ((struct graph$node$$Node*)n) ? ((struct graph$edge$$Edge*)e)->nodes[1] : ((struct graph$edge$$Edge*)e)->nodes[0];
+}
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/edge_picker__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,4 @@
+#pragma once
+
+// [[size 0, align 1]]
+struct graph$edge_picker$$Controller$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "node__tshell.h"
+
+#include "edge__tshell.h"
+#include "edge_picker__tshell.h"
+
+// Note: constant max_edges_per_node expanded here
+struct graph$node$$Node {
+    int num_edges;
+    struct graph$edge$$Edge$$shell *edges[100];
+    struct graph$node$$Other$$shell o;
+};
+
+int graph$node$$add_edge(struct graph$node$$Node$$shell *n, struct graph$edge$$Edge$$shell *e);
+
+int graph$node$$random_search(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int steps_left);
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,37 @@
+#include "node__export.h"
+
+#include "edge__export.h"
+#include "edge_picker__export.h"
+
+#include <stdlib.h>
+
+// move constants to top
+const int graph$node$$max_edges_per_node = 100;
+const int graph$node$$continue_rate = 2;
+
+// also move function declarations (of those not already in `node__export.h`) to top
+int graph$node$$random_search$$mangle(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int *steps_left);
+
+int graph$node$$add_edge(struct graph$node$$Node$$shell *n, struct graph$edge$$Edge$$shell *e) {
+    if (((struct graph$node$$Node*)n)->num_edges >= graph$node$$max_edges_per_node) exit(2);
+    ((struct graph$node$$Node*)n)->edges[((struct graph$node$$Node*)n)->num_edges++] = e;
+    return 1;
+}
+
+int graph$node$$random_search(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int steps_left) {
+    while (steps_left > 0) {
+        int result = graph$node$$random_search$$mangle(start, end, &steps_left);
+        if (result != 0) return result;
+    }
+    return 0;
+}
+
+int graph$node$$random_search$$mangle(struct graph$node$$Node$$shell *start, struct graph$node$$Node$$shell *end, int *steps_left) {
+    if (start == end) return 1;
+    (*steps_left)--;
+    if (rand() % graph$node$$continue_rate == 0) return 0;
+    struct graph$edge_picker$$Controller$$shell c = graph$edge_picker$$get_controller();
+    struct graph$node$$Node$$shell *n = graph$edge_picker$$pick_next(&c, start);
+    if (n == NULL) return 0;
+    return graph$node$$random_search$$mangle(n, end, steps_left);
+}
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph/node__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,9 @@
+#pragma once
+
+// [[size 808, align 8]]
+struct graph$node$$Node$$shell {
+    double contents[101];  // just to fill space, not used
+};
+
+// [[size 0, align 1]]
+struct graph$node$$Other$$shell {};
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__export.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__export.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "graph__tshell.h"
+
+#include "graph/node__tshell.h"
+#include "graph/edge__tshell.h"
+
+struct graph$$Graph {
+    struct graph$node$$Node$$shell *nodes;
+    struct graph$edge$$Edge$$shell *edges;
+    int num_nodes;
+    int num_edges;
+};
+
+struct graph$$Graph$$shell graph$$create_rand_graph(int num_nodes, int num_edges);
+
+struct graph$node$$Node$$shell *graph$$grab_random_node(struct graph$$Graph$$shell *g);
+
+int graph$$path_found(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second);
+
+int graph$$destroy_graph(struct graph$$Graph$$shell *g);
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,38 @@
+#include "graph__export.h"
+
+#include "graph/node__export.h"
+#include "graph/edge__export.h"
+
+#include <stdlib.h>
+
+// move constants to top
+const int graph$$max_steps_to_walk = 1000;
+
+struct graph$$Graph$$shell graph$$create_rand_graph(int num_nodes, int num_edges) {
+    struct graph$$Graph$$shell g;
+    (*(struct graph$$Graph*)&g).num_nodes = num_nodes;
+    (*(struct graph$$Graph*)&g).num_edges = num_edges;
+    (*(struct graph$$Graph*)&g).nodes = (struct graph$node$$Node$$shell *) calloc(num_nodes, sizeof(struct graph$node$$Node$$shell));
+    (*(struct graph$$Graph*)&g).edges = (struct graph$edge$$Edge$$shell *) calloc(num_edges, sizeof(struct graph$edge$$Edge$$shell));
+    for (int i=0; i<num_edges; ++i) {
+        struct graph$node$$Node$$shell *first = graph$$grab_random_node(&g), *second = graph$$grab_random_node(&g);
+        (*(struct graph$$Graph*)&g).edges[i] = graph$edge$$create_edge(first, second);
+        graph$node$$add_edge(first, &(*(struct graph$$Graph*)&g).edges[i]);
+        graph$node$$add_edge(second, &(*(struct graph$$Graph*)&g).edges[i]);
+    }
+    return g;
+}
+
+struct graph$node$$Node$$shell *graph$$grab_random_node(struct graph$$Graph$$shell *g) {
+    return &((struct graph$$Graph*)g)->nodes[rand() % ((struct graph$$Graph*)g)->num_nodes];
+}
+
+int graph$$path_found(struct graph$node$$Node$$shell *first, struct graph$node$$Node$$shell *second) {
+    return graph$node$$random_search(first, second, graph$$max_steps_to_walk);
+}
+
+int graph$$destroy_graph(struct graph$$Graph$$shell *g) {
+    free(((struct graph$$Graph*)g)->nodes);
+    free(((struct graph$$Graph*)g)->edges);
+    return 0;
+}
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__tshell.h
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/graph__tshell.h	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,6 @@
+#pragma once
+
+// [[size 24, align 8]]
+struct graph$$Graph$$shell {
+    double contents[3];  // just to fill space, not used
+};
Index: doc/proposals/modules-alvin/examples/graph/5_tweaking/main__impl.c
===================================================================
--- doc/proposals/modules-alvin/examples/graph/5_tweaking/main__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/5_tweaking/main__impl.c	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,83 @@
+// Graph searching algorithm testing script
+
+#include "graph__export.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void print_usage() {
+    printf("Usage: program_name [-n num_iter] [-s seed] [-N num_nodes] [-E num_edges] [-c num_checks] [-h]\n");
+    printf("Options:\n");
+    printf("  -n num_iter   Number of graphs to run on\n");
+    printf("  -s seed       Seed for random number generator\n");
+    printf("  -N num_nodes  Number of nodes in generated graph\n");
+    printf("  -E num_edges  Number of edges in generated graph\n");
+    printf("  -c num_checks Number of times to check graph for paths\n");
+    printf("  -h            Display this help message\n");
+}
+
+struct Arg {
+    int num_iter, seed, num_nodes, num_edges, num_checks;
+};
+
+struct Arg process_args(int argc, char *argv[]) {
+    int opt;
+    struct Arg args;
+    args.num_iter = 10;
+    args.seed = 0;
+    args.num_nodes = 100;
+    args.num_edges = 100;
+    args.num_checks = 10;
+
+    // Parse command line options
+    while ((opt = getopt(argc, argv, "n:s:N:E:c:h")) != -1) {
+        switch (opt) {
+            case 'n':
+                args.num_iter = atoi(optarg);
+                break;
+            case 's':
+                args.seed = atoi(optarg);
+                break;
+            case 'N':
+                args.num_nodes = atoi(optarg);
+                break;
+            case 'E':
+                args.num_edges = atoi(optarg);
+                break;
+            case 'c':
+                args.num_checks = atoi(optarg);
+                break;
+            case 'h':
+                print_usage(); // Print usage information
+                exit(0);
+            case '?':
+                // Handle unknown options
+                fprintf(stderr, "Unknown option: -%c\n", optopt);
+                print_usage();
+                exit(1);
+            default:
+                print_usage();
+                exit(1);
+        }
+    }
+    return args;
+}
+
+int main(int argc, char *argv[]) {
+    struct Arg args = process_args(argc, argv);
+    int total_paths = 0;
+    srand(args.seed);
+    for (int i=0; i<args.num_iter; ++i) {
+        int paths_found = 0;
+        struct graph$$Graph$$shell g = graph$$create_rand_graph(args.num_nodes, args.num_edges);
+        for (int j=0; j<args.num_checks; ++j) {
+            struct graph$node$$Node$$shell *n2 = graph$$grab_random_node(&g);
+            struct graph$node$$Node$$shell *n1 = graph$$grab_random_node(&g);
+            paths_found += graph$$path_found(n1, n2);  // it's technically returning a bool
+        }
+        graph$$destroy_graph(&g);
+        printf("Graph %d: %d paths found over %d checks.\n", i, paths_found, args.num_checks);
+    }
+    printf("Summary: %d graphs * %d checks = %d total checks performed, %d paths found.\n", args.num_iter, args.num_checks, args.num_iter * args.num_checks, total_paths);
+}
Index: doc/proposals/modules-alvin/examples/graph/info.md
===================================================================
--- doc/proposals/modules-alvin/examples/graph/info.md	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
+++ doc/proposals/modules-alvin/examples/graph/info.md	(revision 7640ff5c2bfadbdbf25492ac84ec6e5be20a4989)
@@ -0,0 +1,51 @@
+Features:
+* Struct, function (no inline), variables
+    * The only definition we need to handle exporting here is struct. typedef, traits, forall, inline functions, we'll look into those later
+    * Also no `export import` (ie. modules that export other module's contents automatically)
+* int, int*, const int
+    * No extra built-in types considered here
+* No `#include`
+    * No manual control over headers demonstrated in example, everything handled in `module`, `import`, `export`
+* No forward decls
+    * All definitions within modules, with declarations automatically hoisted to the top
+    * Note: this requires top-level declarations to be context-free
+
+Stylistic choices:
+* `module;` doesn't specify a namespace (prefix with file path)
+* folder files like `graph.cfa` are outside their folders (simplifies the import file discovery algorithm)
+* `import` uses no quotes/angle brackets (unlike `#include`)
+* `import` automatically opens the namespace (keeping it closed can be tricky with transitive dependencies)
+* `stdio` and other standard C libraries have `import` versions
+* `main.cfa` is not a module (avoid module namespacing interfering with `main()` symbol discovery)
+
+Step-by-step:
+* `0_initial` is the code that is written by the developer
+    * Note how modules seem to have circular dependencies (eg. `graph/node.c` imports `graph/edge.c` and vice versa)
+    * Top-level declarations within modules can also be declared out-of-order (eg. using `a` before `const int a = 4;`)
+* `1_size_analysis` describes a mechanism for figuring out sizes and alignments of types
+    * There could also be an attribute system for indicating a desired size and alignment for a given type (not shown here)
+* `2_tshell` generates the type shell headers
+    * These allow importers to avoid unnecessary dependencies to other modules
+    * eg. if module `A` imports `B`, and `B` imports `C`, then a change to a function in `C` should not cause `A` to recompile
+* `3_export` generates the headers that are imported
+    * Type shells are used in the functions, variables, type definitions
+    * The actual type comes with an implicit zero-cost conversion between it and its type shell
+    * Also note an expansion of the constant `max_edges_per_node` in `graph/node__export.h`
+* `4_impl` generates the implementations
+    * Insert conversions whenever fields of a type are accessed (read or write, though constructors are tricky)
+        * Note that type-punning (eg. `(*(struct S*)&a)`) may not be safe due to [strict aliasing](https://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html) and size/alignment rules not being enforced by the spec
+        * I also don't think I caught every cast (it's enough to compile)
+    * We also move constants and type definitions not already in `__export.h` to the top, as well as adding function declarations
+        * This is what allows top-level declarations to be out-of-order
+* `5_tweaking` alters the library imports to make it compile
+    * ie. `#include <stdio.h>` instead of `#include <stdio__export.h>`
+
+Advanced considerations:
+* No private fields, though opaque types can be made
+* Hoisting occuring at top-level, what about within functions?
+* How does update logic work?
+* No module interface logic here (ie. strong module split)
+* How much of compilation is centrally controlled (ie. by a file that keeps track of the entire project's dependencies)?
+    * `__tshell.h` changes every time a new type is added, but a central file can check if importing files actually need recompilation
+* Extra details: How to perform a unity build? Static/dynamic library generation and management?
+* Aside: Uniform function call syntax
