Gluing tetrahedra together
Rust, 11 (hopefully correct) terms


use ::std::ops::{Add, Sub, Mul};
use ::std::rc::Rc;
use ::std::hash::{Hash, Hasher};
use ::std::collections::HashSet;
use ::std::iter;
use ::std::fmt::{self, Formatter, Display};
use ::std::time::Instant;

type Coord = i128;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Vec3([Coord; 3]);

impl Vec3 {
    fn dot(self, other: Vec3) -&gt; Coord {
        self.0.iter().zip(other.0.iter()).map(|(a, b)| a * b).sum()
    }
}

impl Display for Vec3 {
    fn fmt(&amp;self, f: &amp;mut Formatter) -&gt; fmt::Result {
        write!(f, "({}, {}, {})", self.0[0], self.0[1], self.0[2])
    }
}

impl Mul&lt;Vec3&gt; for Coord {
    type Output = Vec3;

    fn mul(self, mut vec: Vec3) -&gt; Vec3 {
        for i in &amp;mut vec.0 {
            *i *= self;
        }
        vec
    }
}

impl Add for Vec3 {
    type Output = Vec3;

    fn add(mut self, other: Vec3) -&gt; Vec3 {
        for (i, n) in self.0.iter_mut().enumerate() {
            *n += other.0[i];
        }
        self
    }
}

impl Sub for Vec3 {
    type Output = Vec3;

    fn sub(self, other: Vec3) -&gt; Vec3 {
        self + (-1 * other)
    }
}

#[derive(Clone, Debug)]
struct Tetrahedron([Vec3; 4]);

impl Default for Tetrahedron {
    fn default() -&gt; Tetrahedron {
        Tetrahedron([
            Vec3([-1, -1, -1]),
            Vec3([-1,  1,  1]),
            Vec3([ 1, -1,  1]),
            Vec3([ 1,  1, -1]),
        ])
    }
}

impl Display for Tetrahedron {
    fn fmt(&amp;self, f: &amp;mut Formatter) -&gt; fmt::Result {
        write!(f, "Tetrahedron({}, {}, {}, {})", self.0[0], self.0[1], self.0[2], self.0[3])
    }
}

impl Tetrahedron {
    fn collides(&amp;self, other: &amp;Tetrahedron) -&gt; bool {
        let mut othervecs = [3 * self.0[1], 3 * self.0[2], 3 * self.0[3]];
        let sum = self.0[0] + self.0[1] + self.0[2] + self.0[3];
        let mut same = 0;

        for (i, &amp;vec) in self.0.iter().enumerate() {
            let sum = sum - vec;
            let vec = 3 * vec;
            let through = vec - sum;
            for (j, &amp;u) in other.0.iter().enumerate() {
                let u = 3 * u;
                if u == vec { same += 1 }
                let up = (sum - u).dot(through);
                for &amp;v in &amp;other.0[j+1..] {
                    let v = 3 * v;
                    let edge = v - u;
                    let ep = edge.dot(through);

                    if up.signum() != ep.signum() || up.abs() &gt;= ep.abs() {
                        continue
                    }

                    let intersection = ep * u + up * edge;
                    if othervecs.iter().enumerate().all(|(i, &amp;ov)| {
                        let mid = othervecs[(i+1)%3] + othervecs[(i+2)%3];
                        let ov = 2 * ov - mid;
                        (2 * intersection - ep * mid).dot(ep * ov) &gt; 0
                    }) {
                        return true
                    }
                }
            }

            if i != 3 { othervecs[i] = vec; }
        }
        if same == 4 { panic!("EQUAL TETRAHEDRA IN .collides()"); }
        false
    }

    // Mirroring also scales by 3
    fn mirror(&amp;self, i: usize) -&gt; Tetrahedron {
        let mut sum = Vec3([0; 3]);
        for (j, &amp;vec) in self.0.iter().enumerate() {
            if j != i { sum = sum + vec; }
        }

        let mut copy = self.clone();
        copy.scale();

        copy.0[i] = 2 * sum - copy.0[i];
        copy.swap(i, 3);
        copy.rotate_left(i);

        copy
    }

    fn scale(&amp;mut self) {
        for vec in self.0.iter_mut() {
            *vec = 3 * *vec;
        }
    }

    fn rotate_left(&amp;mut self, n: usize) {
        self.0[..3].rotate_left(n)
    }

    fn swap(&amp;mut self, a: usize, b: usize) {
        self.0.swap(a, b)
    }

    fn reverse(&amp;mut self) {
        self.0.reverse()
    }
}

type EndpointIter&lt;'a&gt; = Box&lt;dyn Iterator&lt;Item = Endpoint&gt; + 'a&gt;;

#[derive(Debug, Clone)]
struct Endpoint {
    tree: Rc&lt;TetraTree&gt;,
    hedron: Rc&lt;Tetrahedron&gt;,
}

impl Endpoint {
    fn iter_endpoints(&amp;self) -&gt; EndpointIter {
        let mut hedron = Rc::clone(&amp;self.hedron);
        //Rc::make_mut(&amp;mut hedron).swap(0, 3);
        Rc::make_mut(&amp;mut hedron).reverse();

        Box::new(self.clone().into_iter_directions()
            .chain(self.tree.iter_endpoints(
                Rc::new(TetraTree {
                    subtrees: [None, None, None],
                    hedron,
                })
            ))
        )
    }

    fn into_iter_directions(self) -&gt; EndpointIter&lt;'static&gt; {
        Box::new(iter::successors(Some(self), |this| {
            let mut this = this.clone();
            Rc::make_mut(&amp;mut this.tree).rotate_left(1);
            Rc::make_mut(&amp;mut this.hedron).0[1..].rotate_left(1);
            Some(this)
        }).take(3))
    }

    fn iter_extensions(&amp;self) -&gt; EndpointIter {
        let mut tree = self.tree.as_ref().clone();
        tree.scale();

        let mut hedron = self.hedron.as_ref().clone();
        //hedron.swap(0, 3);
        hedron.reverse();
        hedron.scale();

        Box::new(Endpoint {
            tree: Rc::new(tree),
            hedron: Rc::clone(&amp;self.hedron),
        }.into_iter_directions().filter_map(|endpoint| {
            let mut new = endpoint.hedron.mirror(3);
            new.swap(0, 3);
            if endpoint.tree.collides(&amp;new) {
                None
            } else {
                let mut hedron = endpoint.hedron;
                Rc::make_mut(&amp;mut hedron).scale();

                Some(Endpoint {
                    tree: Rc::new(TetraTree {
                        subtrees: [Some(endpoint.tree), None, None],
                        hedron,
                    }),
                    hedron: Rc::new(new),
                })
            }
        }).chain(self.tree.iter_extensions(Rc::new(TetraTree {
            subtrees: [None, None, None],
            hedron: Rc::new(hedron),
        }))))
    }

    fn iter_tetrahedra&lt;'a&gt;(&amp;'a self)
      -&gt; Box&lt;dyn Iterator&lt;Item = &amp;Tetrahedron&gt; + 'a&gt; {
        Box::new(
          iter::once(self.hedron.as_ref()).chain(self.tree.iter_tetrahedra())
        )
    }
}

impl Default for Endpoint {
    fn default() -&gt; Endpoint {
        Endpoint::from(Tetrahedron::default())
    }
}

impl From&lt;Tetrahedron&gt; for Endpoint {
    fn from(mut hedron: Tetrahedron) -&gt; Endpoint {
        let mirrored = hedron.mirror(0);
        hedron.scale();

        Endpoint {
            tree: Rc::new(TetraTree {
                subtrees: [None, None, None],
                hedron: Rc::new(mirrored),
            }),
            hedron: Rc::new(hedron),
        }
    }
}

impl Hash for Endpoint {
    fn hash&lt;H: Hasher&gt;(&amp;self, hasher: &amp;mut H) {
        let mut stuff: Vec&lt;_&gt; = self.tree.hash_helper(1).collect();
        stuff.push(self.tree.len());
        stuff.sort();
        stuff.hash(hasher);
    }
}

impl PartialEq for Endpoint {
    fn eq(&amp;self, other: &amp;Endpoint) -&gt; bool {
        self.iter_endpoints().any(|ep| ep.tree == other.tree)
    }
}

impl Eq for Endpoint {}

#[derive(Debug, Clone)]
struct TetraTree {
    subtrees: [Option&lt;Rc&lt;TetraTree&gt;&gt;; 3],
    hedron: Rc&lt;Tetrahedron&gt;,
}

impl TetraTree {
    fn iter_endpoints&lt;'x&gt;(&amp;'x self, behind: Rc&lt;TetraTree&gt;) -&gt; EndpointIter&lt;'x&gt; {
        let mut iterator = self.subtrees.iter().enumerate()
          .filter_map(|(i, opt)| opt.as_ref().map(|some| (i, some)));

        if let Some(first) = iterator.next() {
            let closure = move |(i, subtree): (usize, &amp;'x Rc&lt;TetraTree&gt;)| -&gt; EndpointIter&lt;'x&gt; {
                let mut behind = behind.as_ref().clone();
                behind.rotate_left(3-i);

                let mut this = self.clone();
                this.rotate_left(i);

                Rc::make_mut(&amp;mut this.hedron).reverse();

                this.subtrees.swap(1, 2);
                this.subtrees[0] = Some(Rc::new(behind));

                for (j, subtree) in this.subtrees.iter_mut().enumerate().skip(1)
                  .filter_map(|(j, s)| s.as_mut().map(|s| (j, s))) {
                    Rc::make_mut(subtree).rotate_left(j);
                }

                subtree.iter_endpoints(Rc::new(this))
            };
            Box::new(closure(first).chain(iterator.flat_map(closure)))
        } else {
            let mut hedron = self.hedron.as_ref().clone();
            //hedron.swap(0, 3);
            hedron.reverse();
            Endpoint {
                tree: Rc::clone(&amp;behind),
                hedron: Rc::new(hedron),
            }.into_iter_directions()
        }
    }

    fn rotate_left(&amp;mut self, i: usize) {
        self.subtrees.rotate_left(i);
        Rc::make_mut(&amp;mut self.hedron).rotate_left(i);
    }

    fn collides(&amp;self, hedron: &amp;Tetrahedron) -&gt; bool {
        self.hedron.collides(hedron) ||
          self.subtrees.iter()
            .filter_map(Option::as_ref)
            .any(|subtree| subtree.collides(hedron))
    }

    fn scale(&amp;mut self) {
        for subtree in self.subtrees.iter_mut().filter_map(Option::as_mut) {
            Rc::make_mut(subtree).scale();
        }
        Rc::make_mut(&amp;mut self.hedron).scale();
    }

    fn iter_extensions(&amp;self, behind: Rc&lt;TetraTree&gt;) -&gt; EndpointIter {
        Box::new(self.subtrees.iter().enumerate().flat_map(move |(i, next)| {
            let mut behind = behind.as_ref().clone();
            behind.rotate_left(3-i);

            let mut this = self.clone();
            this.rotate_left(i);

            let hedron = Rc::make_mut(&amp;mut this.hedron);
            hedron.reverse();

            this.subtrees.swap(1, 2);
            this.subtrees[0] = Some(Rc::new(behind));

            for (j, subtree) in this.subtrees.iter_mut().enumerate().skip(1)
              .filter_map(|(j, s)| s.as_mut().map(|s| (j, s))) {
                let subtree = Rc::make_mut(subtree);
                subtree.scale();
                subtree.rotate_left(j);
            }

            if let Some(next) = next {
                hedron.scale();
                next.iter_extensions(Rc::new(this))
            } else {
                let mut mirrored = hedron.mirror(3);
                mirrored.swap(0, 3);
                hedron.scale();

                if this.collides(&amp;mirrored) {
                    Box::new(iter::empty()) as EndpointIter
                } else {
                    Box::new(iter::once(Endpoint {
                        tree: Rc::new(this),
                        hedron: Rc::new(mirrored),
                    }))
                }
            }
        }))
    }

    fn iter_tetrahedra&lt;'a&gt;(&amp;'a self)
      -&gt; Box&lt;dyn Iterator&lt;Item = &amp;Tetrahedron&gt; + 'a&gt; {
        Box::new(iter::once(self.hedron.as_ref()).chain(
          self.subtrees.iter()
            .filter_map(Option::as_deref)
            .flat_map(TetraTree::iter_tetrahedra)
        ))
    }

    fn len(&amp;self) -&gt; usize {
        1usize + self.subtrees.iter()
              .filter_map(Option::as_deref).map(TetraTree::len).sum::&lt;usize&gt;()
    }

    fn hash_helper&lt;'a&gt;(&amp;'a self, behind: usize)
      -&gt; Box&lt;dyn Iterator&lt;Item = usize&gt; + 'a&gt; {
        let sub: Vec&lt;_&gt; = self.subtrees.iter().filter_map(Option::as_deref)
          .map(|a| (a, a.len())).collect();
        let sum = sub.iter()
          .map(|&amp;(_, len)| len).sum::&lt;usize&gt;() + behind + 1;
        Box::new(iter::once(behind).chain(
            sub.into_iter().flat_map(move |(sub, len)|
                        iter::once(len).chain(sub.hash_helper(sum - len)))
        ))
    }
}

impl PartialEq for TetraTree {
    fn eq(&amp;self, rhs: &amp;TetraTree) -&gt; bool {
        self.subtrees == rhs.subtrees
    }
}

impl Eq for TetraTree {}

fn main() {
    let verbose = std::env::args().skip(1).any(|arg| arg == "-v");
    let begin = Instant::now();

    println!("1: 1 [{}ms]", begin.elapsed().as_millis());
    if verbose {
        println!("{}\n--", Tetrahedron::default());
    }

    let mut polytets = HashSet::new();
    polytets.insert(Endpoint::default());

    for i in 2.. {
        println!("{}: {} [{}ms]", i, polytets.len(), begin.elapsed().as_millis());

        if verbose {
            for polytet in &amp;polytets {
                for hedron in polytet.iter_tetrahedra() {
                    println!("{}", hedron);
                }
                println!("--");
            }
        }

        polytets = polytets.iter()
          .flat_map(Endpoint::iter_extensions)
          .collect();
    }
}


Try it online! The footer contains some compatability implementations because TIO's Rust is a little old. (This has already been reported and added to the list.)
Output:
1: 1 [0ms]
2: 1 [0ms]
3: 1 [2ms]
4: 4 [8ms]
5: 10 [35ms]
6: 39 [139ms]
7: 164 [738ms]
8: 767 [4328ms]
9: 3656 [31298ms]
10: 18186 [287871ms]
11: 91532 [3154716ms]

As you can see, it also reports how long it took. (These are cumulated times.) You can use the -v option to list all tetrahedra for each polytet.
I don't really have a good way of verifying the results beyond A267272(5). I hope it works, but I'm not sure.
The idea is that we store the polytet as a tree of tetrahedra that also encodes orientation. But for collision detection we need actual tetrahedra. We start with the tetrahedron with vertices (-1, -1, -1), (-1, 1, 1), (1, -1, 1), (1, 1, -1) and scale all tetrahedra by 3 for every term. This avoids the need for fractions.
Can probably be made faster, but I don't know how.