diff --git a/WORKSPACE b/WORKSPACE
index 0528d59..6731735 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -62,18 +62,18 @@ load("@arrdem_source_pypi//:requirements.bzl", "install_deps")
 # Call it to define repos for your requirements.
 install_deps()
 
-git_repository(
-   name = "rules_zapp",
-   remote = "https://git.arrdem.com/arrdem/rules_zapp.git",
-   commit = "961be891e5cff539e14f2050d5cd9e82845ce0f2",
-   # tag = "0.1.2",
-)
-
-# local_repository(
-#     name = "rules_zapp",
-#     path = "/home/arrdem/Documents/hobby/programming/lang/python/rules_zapp",
+# git_repository(
+#    name = "rules_zapp",
+#    remote = "https://git.arrdem.com/arrdem/rules_zapp.git",
+#    commit = "72f82e0ace184fe862f1b19c4f71c3bc36cf335b",
+#    # tag = "0.1.2",
 # )
 
+local_repository(
+    name = "rules_zapp",
+    path = "/home/arrdem/Documents/hobby/programming/lang/python/rules_zapp",
+)
+
 ####################################################################################################
 # Docker support
 ####################################################################################################
diff --git a/projects/proquint/BUILD b/projects/proquint/BUILD
index c55fdfd..05257fc 100644
--- a/projects/proquint/BUILD
+++ b/projects/proquint/BUILD
@@ -8,7 +8,6 @@ py_project(
 zapp_binary(
     name = "qint",
     main = "src/python/proquint/__main__.py",
-    shebang = "#!/usr/bin/env python3",
     imports = [
         "src/python",
     ],
diff --git a/projects/tentacles/src/python/gcode.py b/projects/tentacles/src/python/gcode.py
deleted file mode 100644
index 4131aef..0000000
--- a/projects/tentacles/src/python/gcode.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env python3
-
-from pathlib import Path
-from attrs import define
-from typing import Optional, Tuple
-
-import re
-
-OPTION_PATTERN = re.compile("; (?P<key>[a-z0-9_]+) = (?P<value>.*?)\n")
-
-
-def parse_prusa_config_str(content: str) -> dict:
-    kvs = {}
-    iter = re.finditer(OPTION_PATTERN, content)
-    while m := next(iter, None):
-        if m.group("key") == "prusaslicer_config" and m.group("value") == "begin":
-            break
-    while m := next(iter, None):
-        if m.group("key") == "prusaslicer_config" and m.group("value") == "end":
-            break
-        else:
-            kvs[m.group("key")] = m.group("value")
-
-    return kvs
-
-
-def parse_prusa_config(p: Path):
-    with open(p) as fp:
-        return parse_prusa_config_str(fp.read())
-
-
-@define
-class GcodeAnalysis:
-    max_x: int
-    max_y: int
-    max_z: int
-    max_bed: int
-    max_end: int
-    filament: str
-    nozzle: int
-
-
-def parse_point(point: str) -> Tuple[int, int]:
-    a, b = point.split("x")
-    return int(a), int(b)
-
-
-def parse_bed_shape(coords: str) -> Tuple[int, int]:
-    # Note, these are clockwise from 0, 0
-    a, b, c, d = coords.split(",")
-    dx, _ = parse_point(a)
-    _, dy = parse_point(b)
-    x, y = parse_point(c)
-    return x + dx, y + dy
-
-
-def analyze_gcode_str(text: str) -> Optional[GcodeAnalysis]:
-    opts = parse_prusa_config_str(text)
-
-    kwargs = {}
-    if "bed_shape" in opts:
-        max_x, max_y = parse_bed_shape(opts["bed_shape"])
-        kwargs["max_x"] = max_x
-        kwargs["max_y"] = max_y
-    else:
-        return None
-
-    if "max_print_height" in opts:
-        kwargs["max_z"] = int(opts["max_print_height"])
-    else:
-        return None
-
-    if "first_layer_bed_temperature" in opts:
-        kwargs["max_bed"] = int(opts["first_layer_bed_temperature"])
-    elif "bed_temperature" in opts:
-        kwargs["max_bed"] = int(opts["bed_temperature"])
-    else:
-        return None
-
-    if "first_layer_temperature" in opts:
-        kwargs["max_end"] = int(opts["first_layer_temperature"])
-    elif "temperature" in opts:
-        kwargs["max_end"] = int(opts["temperature"])
-    else:
-        return None
-
-    if "filament_type" in opts:
-        kwargs["filament"] = opts["filament_type"]
-    else:
-        return None
-
-    if "nozzle_diameter" in opts:
-        kwargs["nozzle"] = float(opts["nozzle_diameter"])
-    else:
-        return None
-
-    return GcodeAnalysis(**kwargs)
-
-
-def analyze_gcode_file(p: Path) -> Optional[GcodeAnalysis]:
-    with open(p) as fp:
-        return analyze_gcode_str(fp.read())
diff --git a/projects/tentacles/src/python/tentacles/__main__.py b/projects/tentacles/src/python/tentacles/__main__.py
index ddd310f..fca1a97 100644
--- a/projects/tentacles/src/python/tentacles/__main__.py
+++ b/projects/tentacles/src/python/tentacles/__main__.py
@@ -143,13 +143,12 @@ def serve(hostname: str, port: int, config: Path, trace: bool):
 
     # Spawn the worker thread(s)
     Worker(cherrypy.engine, app, db_factory, poll_printers, frequency=5).start()
-    Worker(cherrypy.engine, app, db_factory, analyze_files, frequency=5).start()
     Worker(cherrypy.engine, app, db_factory, assign_jobs, frequency=5).start()
     Worker(cherrypy.engine, app, db_factory, push_jobs, frequency=5).start()
     Worker(cherrypy.engine, app, db_factory, revoke_jobs, frequency=5).start()
     Worker(cherrypy.engine, app, db_factory, pull_jobs, frequency=5).start()
     Worker(cherrypy.engine, app, db_factory, send_emails, frequency=5).start()
-    # Worker(cherrypy.engine, app, db_factory, debug_queue, frequency=5).start()
+    Worker(cherrypy.engine, app, db_factory, debug_queue, frequency=5).start()
 
     # Run the server
     cherrypy.engine.start()
diff --git a/projects/tentacles/src/python/tentacles/db.py b/projects/tentacles/src/python/tentacles/db.py
index 4fdf900..237c2f4 100644
--- a/projects/tentacles/src/python/tentacles/db.py
+++ b/projects/tentacles/src/python/tentacles/db.py
@@ -182,9 +182,6 @@ class Db(Queries):
         digest.update(password.encode("utf-8"))
         res = super().try_login(username=username, hash=digest.hexdigest())
         if not res:
-            print("WARNING: Failed to log in!")
-            for it in self._cursor.execute("SELECT * FROM users").fetchall():
-                print("DEBUG", it)
             return None
 
         return self.create_key(uid=res.id, name="web session", ttl=ttl)
diff --git a/projects/tentacles/src/python/tentacles/sql/files.sql b/projects/tentacles/src/python/tentacles/sql/files.sql
index 9a53828..9b2760e 100644
--- a/projects/tentacles/src/python/tentacles/sql/files.sql
+++ b/projects/tentacles/src/python/tentacles/sql/files.sql
@@ -8,19 +8,6 @@ CREATE TABLE IF NOT EXISTS files (
  , FOREIGN KEY(user_id) REFERENCES user(id)
 );
 
--- name: migration-0004-create-file-analysis#
-CREATE TABLE IF NOT EXISTS file_analysis (
-   id INTEGER PRIMARY KEY AUTOINCREMENT
- , max_x INTEGER
- , max_y INTEGER
- , max_z INTEGER
- , max_end INTEGER
- , max_bed INTEGER
- , nozzle_diameter FLOAT
- , filament_id INTEGER REFERENCES filament(id)
- , file_id INTEGER REFERENCES file(id)
-);
-
 -- name: create-file^
 INSERT INTO files (
    user_id
@@ -58,41 +45,3 @@ WHERE
    user_id = :uid
    AND id = :fid
 ;
-
--- name: create-analysis^
-INSERT INTO file_analysis (
-   max_x
- , max_y
- , max_z
- , max_end
- , max_bed
- , nozzle_diameter
- , filament_id
- , file_id
-)
-VALUES (
-   :max_x
- , :max_y
- , :max_z
- , :max_end
- , :max_bed
- , :nozzle
- , :filament_id
- , :file_id
-)
-RETURNING
-  id
-;
-
--- name: list-unanalyzed-files
-SELECT
-   f.id
- , f.path
- , f.filename
- , f.user_id
-FROM files f
-LEFT JOIN file_analysis fa
-   ON f.id = fa.file_id
-WHERE
-   fa.file_id IS NULL
-;
diff --git a/projects/tentacles/src/python/tentacles/sql/jobs.sql b/projects/tentacles/src/python/tentacles/sql/jobs.sql
index 7c9ef2b..f1eaf7e 100644
--- a/projects/tentacles/src/python/tentacles/sql/jobs.sql
+++ b/projects/tentacles/src/python/tentacles/sql/jobs.sql
@@ -68,25 +68,11 @@ WHERE
 
 -- name: list-job-queue
 SELECT
-   j.id as id
- , j.file_id
- , fa.id as analysis_id
- , fa.max_x
- , fa.max_y
- , fa.max_z
- , fa.max_bed
- , fa.max_end
- , fa.nozzle_diameter
- , fa.filament_id
-FROM jobs j
-INNER JOIN files f
-  ON j.file_id = f.id
-LEFT JOIN file_analysis fa
-  ON fa.file_id = f.id
+   *
+FROM jobs
 WHERE
    finished_at IS NULL
-   AND (:uid IS NULL OR j.user_id = :uid)
-   AND f.id IS NOT NULL
+   AND (:uid IS NULL OR user_id = :uid)
 ;
 
 -- name: poll-job-queue^
diff --git a/projects/tentacles/src/python/tentacles/sql/printers.sql b/projects/tentacles/src/python/tentacles/sql/printers.sql
index 3901f46..f3e6980 100644
--- a/projects/tentacles/src/python/tentacles/sql/printers.sql
+++ b/projects/tentacles/src/python/tentacles/sql/printers.sql
@@ -41,7 +41,7 @@ CREATE TABLE IF NOT EXISTS printer_chassis (
 );
 
 INSERT INTO printer_chassis (name, limit_x, limit_y, limit_z, limit_bed, limit_hotend, limit_tools) VALUES (
-   'Creality CR-10v3', 310, 310, 400, 100, 260, 1
+   'Creality CR-10v3', 300, 300, 400, 100, 260, 1
 );
 
 INSERT INTO printer_chassis (name, limit_x, limit_y, limit_z, limit_bed, limit_hotend, limit_tools) VALUES (
@@ -76,7 +76,7 @@ ALTER TABLE printers ADD filament_id INTEGER REFERENCES filament(id) DEFAULT 1;
 ALTER TABLE printers ADD enabled BOOLEAN DEFAULT TRUE;
 
 -- name: migration-0005-create-printer-nozzle#
-ALTER TABLE printers ADD nozzle_diameter FLOAT DEFAULT 0.4;
+ALTER TABLE printers ADD nozzle_diameter INTEGER default 4;
 
 -- name: try-create-printer^
 INSERT INTO printers (
@@ -116,19 +116,8 @@ SELECT
  , p.api_key
  , p.last_poll_date
  , s.name as status
- , p.enabled
- , f.name as filament_name
- , c.name as machine_name
- , c.limit_x
- , c.limit_y
- , c.limit_z
- , c.limit_bed
- , c.limit_hotend
- , p.nozzle_diameter
 FROM printers p
 INNER JOIN printer_statuses s ON p.status_id = s.id
-INNER JOIN filament f on p.filament_id = f.id
-INNER JOIN printer_chassis c on p.chassis_id = c.id
 ;
 
 -- name: list-idle-printers
@@ -137,8 +126,9 @@ SELECT
  , c.limit_x
  , c.limit_y
  , c.limit_z
- , c.limit_bed
  , c.limit_hotend
+ , c.limit_bed
+ , c.limit_tools
  , p.nozzle_diameter
 FROM printers p
 LEFT JOIN (SELECT id, printer_id FROM jobs WHERE finished_at IS NULL) j
@@ -191,14 +181,3 @@ SELECT
  , name
  FROM filament
  ;
-
--- name: create-filament^
-INSERT OR IGNORE INTO filament (
-   name
-)
-VALUES (
-   :name
-)
-RETURNING
-   id
-;
diff --git a/projects/tentacles/src/python/tentacles/sql/user_keys.sql b/projects/tentacles/src/python/tentacles/sql/user_keys.sql
index 9d841ef..54d2c69 100644
--- a/projects/tentacles/src/python/tentacles/sql/user_keys.sql
+++ b/projects/tentacles/src/python/tentacles/sql/user_keys.sql
@@ -77,8 +77,7 @@ INNER JOIN users u
 WHERE
    (expiration IS NULL OR unixepoch(expiration) > unixepoch('now'))
    AND k.id = :kid
-   AND (u.enabled_at IS NOT NULL -- and the user is not disabled!
-        OR u.group_id = 0)       -- or the user is a root
+   AND u.enabled_at IS NOT NULL -- and the user is not disabled!
 ;
 
 -- name: refresh-key
diff --git a/projects/tentacles/src/python/tentacles/static/css/style.scss b/projects/tentacles/src/python/tentacles/static/css/style.scss
index 934724c..69be564 100644
--- a/projects/tentacles/src/python/tentacles/static/css/style.scss
+++ b/projects/tentacles/src/python/tentacles/static/css/style.scss
@@ -58,10 +58,6 @@ label {
   flex: 1;
 }
 
-.u-flex-wrap {
-  flex-wrap: wrap;
-}
-
 @media (max-width: 760px) {
   .file, .printer, .key, .job {
     flex-direction: column;
diff --git a/projects/tentacles/src/python/tentacles/templates/files_list.html.j2 b/projects/tentacles/src/python/tentacles/templates/files_list.html.j2
index 632bb7c..6861143 100644
--- a/projects/tentacles/src/python/tentacles/templates/files_list.html.j2
+++ b/projects/tentacles/src/python/tentacles/templates/files_list.html.j2
@@ -4,10 +4,10 @@
 {% if files %}
 {% for file in files %}
 <div class="file row u-flex">
-  <div class="details six columns u-flex u-flex-wrap">
+  <div class="details six columns">
     <span class="file-name">{{ file.filename }}</span>
-    <span class="file-sucesses">{{ file.print_successes }} successes</span>
-    <span class="file-failures">{{ file.print_failures }} errors</span>
+    <span class="file-sucesses">{{ file.print_successes }}</span> successes
+    <span class="file-failures">{{ file.print_failures }}</span> errors
   </div>
   <div class="controls u-flex u-ml-auto">
     {{ macros.start_job(file.id) }}
diff --git a/projects/tentacles/src/python/tentacles/templates/jobs_history.html.j2 b/projects/tentacles/src/python/tentacles/templates/jobs_history.html.j2
index 68441ed..cadc3c4 100644
--- a/projects/tentacles/src/python/tentacles/templates/jobs_history.html.j2
+++ b/projects/tentacles/src/python/tentacles/templates/jobs_history.html.j2
@@ -4,10 +4,11 @@
 {% if jobs %}
 {% for job in jobs %}
 <div class="job row u-flex">
-  <div class="details six columns u-flex u-flex-wrap">
-    <div class="job-filename u-flex">
-      <label for="filename">File</label>
-      <span name="filename">{{ctx.db.fetch_file(ctx.uid, job.file_id).filename or "it's a secret"}}</span>
+  <div class="details six columns u-flex">
+    <div class="job-status u-flex">
+      <label for="state">Job</label>
+      <div class="dot {{ macros.job_state(job) }}" style="--dot-size: 1em;"> </div>
+      <span name="state">{{ macros.job_state(job) }}</span>
     </div>
     {% if job.printer_id %}
     <div class="job-printer u-flex">
@@ -15,20 +16,18 @@
       <span name="printer">{{ ctx.db.fetch_printer(job.printer_id).name }}</span>
     </div>
     {% endif %}
+    <div class="job-filename u-flex">
+      <label for="filename">File</label>
+      <span name="filename">{{ctx.db.fetch_file(ctx.uid, job.file_id).filename or "it's a secret"}}</span>
+    </div>
     {% if job.finished_at and job.started_at %}
     <div class="job-runtime u-flex">
       <label for="runtime">Runtime</label>
       <span name="Runtime">{{ (datetime.fromisoformat(job.finished_at) - datetime.fromisoformat(job.started_at)) }}</span>
     </div>
     {% endif %}
-  </div>
-  <div class="two columns">
-    <div class="job-status u-flex">
-      <label for="state">Status</label>
-      <div class="dot {{ macros.job_state(job) }} tooltip bottom" data-text="{{ macros.job_state(job) }}" style="--dot-size: 1em;"> </div>
     </div>
-  </div>
-  <div class="controls four columns u-flex u-ml-auto">
+  <div class="controls u-flex u-ml-auto">
     {% if ctx.uid %}
     {{ macros.duplicate_job(job.id) }}
     {{ macros.delete_job(job.id) }}
diff --git a/projects/tentacles/src/python/tentacles/templates/jobs_list.html.j2 b/projects/tentacles/src/python/tentacles/templates/jobs_list.html.j2
index ef7599c..1846eb6 100644
--- a/projects/tentacles/src/python/tentacles/templates/jobs_list.html.j2
+++ b/projects/tentacles/src/python/tentacles/templates/jobs_list.html.j2
@@ -5,9 +5,10 @@
 {% for job in jobs %}
 <div class="job row u-flex">
   <div class="details six columns u-flex">
-    <div class="job-filename u-flex">
-      <label for="filename">File</label>
-      <span name="filename">{{ctx.db.fetch_file(ctx.uid, job.file_id).filename or "it's a secret"}}</span>
+    <div class="job-status u-flex">
+      <label for="state">Job</label>
+      <div class="dot {{ macros.job_state(job) }} {{ 'dot--basic' if not job.state else '' }}" style="--dot-size: 1em;"> </div>
+      <span name="state">{{ macros.job_state(job) }}</span>
     </div>
     {% if job.printer_id %}
     <div class="job-printer u-flex">
@@ -15,6 +16,10 @@
       <span name="printer">{{ ctx.db.fetch_printer(job.printer_id).name }}</span>
     </div>
     {% endif %}
+    <div class="job-filename u-flex">
+      <label for="filename">File</label>
+      <span name="filename">{{ctx.db.fetch_file(ctx.uid, job.file_id).filename or "it's a secret"}}</span>
+    </div>
     {% if job.started_at %}
     <div class="job-runtime u-flex">
       <label for="runtime">Runtime</label>
@@ -22,12 +27,6 @@
     </div>
     {% endif %}
   </div>
-  <div class="two columns">
-    <div class="job-status u-flex">
-      <label for="state">Status</label>
-      <div class="dot {{ macros.job_state(job) }} tooltip bottom" data-text="{{ macros.job_state(job) }}" style="--dot-size: 1em;"> </div>
-    </div>
-  </div>
   <div class="controls u-flex u-ml-auto">
     {% if ctx.uid %}
     {{ macros.duplicate_job(job.id) }}
diff --git a/projects/tentacles/src/python/tentacles/templates/streams.html.j2 b/projects/tentacles/src/python/tentacles/templates/streams.html.j2
index 450ca89..16d8713 100644
--- a/projects/tentacles/src/python/tentacles/templates/streams.html.j2
+++ b/projects/tentacles/src/python/tentacles/templates/streams.html.j2
@@ -6,10 +6,6 @@
     <div class="u-flex1 webcam" style="max-width: calc(100% / {{printers|length}})">
       <label>{{ printer.name }}</label>
       <img id="printer_{{printer.id}}_stream" src="{{ printer.stream_url }}" style="max-width: 100%;" />
-      <span><label>Status</label>{{printer.status}}, {% if printer.enabled %}accepting jobs{%else%}not scheduling{%endif%}</span>
-      <span><label>Loaded material</label>{{printer.filament_name}}</span>
-      <span><label>Machine</label>{{printer.machine_name}}</span>
-      <span><label>Limits</label>{{printer.limit_x}}mm x{{printer.limit_y}}mm x{{printer.limit_z}}mm, bed {{printer.limit_bed}}c, end {{printer.limit_hotend}}c</span>
     </div>
   {% endfor %}
 </div>
diff --git a/projects/tentacles/src/python/tentacles/workers.py b/projects/tentacles/src/python/tentacles/workers.py
index dff20cb..956cc5d 100644
--- a/projects/tentacles/src/python/tentacles/workers.py
+++ b/projects/tentacles/src/python/tentacles/workers.py
@@ -17,7 +17,6 @@ from urllib import parse as urlparse
 
 from cherrypy.process.plugins import Monitor
 from fastmail import FastMailSMTP
-from gcode import analyze_gcode_file
 from flask import Flask as App
 from octorest import OctoRest as _OR
 from requests import Response
@@ -147,20 +146,10 @@ def poll_printers(app: App, db: Db) -> None:
 def assign_jobs(app: App, db: Db) -> None:
     """Assign jobs to printers. Uploading files and job state management is handled separately."""
 
-    for job in db.list_job_queue(uid=None):
-        for printer in db.list_idle_printers():
-            if (
-                printer.limit_x >= job.max_x
-                and printer.limit_y >= job.max_y
-                and printer.limit_z >= job.max_z
-                and printer.limit_hotend >= job.max_end
-                and printer.limit_bed >= job.max_bed
-                and printer.nozzle_diameter == job.nozzle_diameter
-                and printer.filament_id == job.filament_id
-            ):
-                db.assign_job(jid=job.id, pid=printer.id)
-                log.info(f"Mapped job {job.id} to printer {printer.id}")
-                break
+    for printer in db.list_idle_printers():
+        if job := db.poll_job_queue():
+            db.assign_job(jid=job.id, pid=printer.id)
+            log.info(f"Mapped job {job.id} to printer {printer.id}")
 
 
 def push_jobs(app: App, db: Db) -> None:
@@ -301,41 +290,14 @@ def send_emails(app, db: Db):
             db.send_email(eid=message.id)
 
 
-def analyze_files(app: App, db: Db):
-    for unanalyzed in db.list_unanalyzed_files():
-        record = analyze_gcode_file(Path(unanalyzed.path))
-        if not record:
-            log.error(
-                f"Unable to analyze {unanalyzed.path} ({unanalyzed.filename} owned by {unanalyzed.user_id})!"
-            )
-            continue
-
-        db.create_analysis(
-            file_id=unanalyzed.id,
-            max_x=record.max_x,
-            max_y=record.max_y,
-            max_z=record.max_z,
-            max_end=record.max_end,
-            max_bed=record.max_bed,
-            filament_id=db.create_filament(record.filament),
-        )
-
-
 def debug_queue(app: App, db: Db):
     output = ["---"]
-
-    for job in db.list_job_queue(uid=None):
-        output.append("Job " + repr(job))
-
+    for job in db.list_running_jobs():
+        output.append(repr(job))
     for printer in db.list_idle_printers():
-        output.append("Printer " + repr(printer))
-
-    for unanalyzed in db.list_unanalyzed_files():
-        output.append("Unanalyzed file " + repr(unanalyzed))
-
+        output.append(repr(printer))
     print("\n".join(output))
 
-
 def toil(*fs):
     def _helper(*args, **kwargs):
         for f in fs:
diff --git a/projects/tentacles/test/python/conftest.py b/projects/tentacles/test/python/conftest.py
index 3121717..a44ce2a 100644
--- a/projects/tentacles/test/python/conftest.py
+++ b/projects/tentacles/test/python/conftest.py
@@ -1,21 +1,15 @@
 #!/usr/bin/env python3
 
 from datetime import timedelta
-import logging
 
 import pytest
 from tentacles.db import Db
 
-# FIXME: Should this be an autouse fixture? Maybe. Doesn't buy much tho.
-logging.addLevelName(logging.DEBUG - 5, "TRACE")
-logging.TRACE = logging.DEBUG - 5
 
-
-@pytest.fixture
+@pytest.yield_fixture
 def db():
     conn = Db(":memory:")
     conn.connect()
-    conn.migrate()
     yield conn
     conn.close()
 
@@ -31,23 +25,26 @@ def password_testy():
 
 
 @pytest.fixture
-def uid_testy(db: Db, username_testy, password_testy) -> int:
-    return db.try_create_user(
-        username=username_testy,
-        email=username_testy,
-        password=password_testy,
-        sid=1,
-        gid=0,  # Note: to bypass the approve/enable machinery
-    ).id
+def uid_testy(db: Db, username_testy, password_testy):
+    with db.savepoint():
+        return db.try_create_user(
+            username=username_testy,
+            email=username_testy,
+            password=password_testy,
+            sid=1,
+        ).id
 
 
 @pytest.fixture
-def login_ttl() -> timedelta:
+def login_ttl():
     return timedelta(hours=12)
 
 
 @pytest.fixture
 def sid_testy(db: Db, uid_testy, username_testy, password_testy, login_ttl):
-    res = db.try_login(username=username_testy, password=password_testy, ttl=login_ttl)
-    assert res.user_id == uid_testy
-    return res.id
+    with db.savepoint():
+        res = db.try_login(
+            username=username_testy, password=password_testy, ttl=login_ttl
+        )
+        assert res.user_id == uid_testy
+        return res.id
diff --git a/projects/tentacles/test/python/test_gcode.py b/projects/tentacles/test/python/test_gcode.py
deleted file mode 100644
index 5f1164a..0000000
--- a/projects/tentacles/test/python/test_gcode.py
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env python3
-
-import re
-
-from gcode import (
-    parse_prusa_config_str,
-    OPTION_PATTERN,
-    analyze_gcode_str,
-    GcodeAnalysis,
-)
-
-
-def test_option_pattern():
-    assert re.match(OPTION_PATTERN, "\n") is None
-    assert re.findall(OPTION_PATTERN, "; foo = bar\n")
-    assert re.findall(OPTION_PATTERN, "; foo = bar\n; baz = qux")
-
-
-def test_parse_config_str():
-    assert parse_prusa_config_str("") == {}
-    assert (
-        parse_prusa_config_str(
-            """
-; prusaslicer_config = begin
-; foo = bar
-; prusaslicer_config = end
-    """
-        )
-        == {"foo": "bar"}
-    )
-
-
-def test_analyze_gcode():
-    assert (
-        analyze_gcode_str(
-            """
-
-gcode garbage
-
-; some comment
-more garbage
-
-; prusaslicer_config = begin
-; bed_shape = 5x5,95x5,95x95,5x95
-; max_print_height = 100
-; first_layer_bed_temperature = 100
-; first_layer_temperature = 195
-; filament_type = PETG
-; nozzle_diameter = 1.0
-; prusaslicer_config = end
-
-"""
-        )
-        == GcodeAnalysis(100, 100, 100, 100, 195, "PETG", 1.0)
-    )
diff --git a/projects/tentacles/test/python/test_store.py b/projects/tentacles/test/python/test_store.py
index 8e3928b..3493188 100644
--- a/projects/tentacles/test/python/test_store.py
+++ b/projects/tentacles/test/python/test_store.py
@@ -3,12 +3,12 @@
 from tentacles.db import Db
 
 
-def test_db_initializes(db: Db):
-    assert isinstance(db, Db)
+def test_db_initializes(store: Db):
+    assert isinstance(store, Db)
 
 
-def test_db_savepoint(db: Db):
-    obj = db.savepoint()
+def test_db_savepoint(store: Db):
+    obj = store.savepoint()
 
     assert hasattr(obj, "__enter__")
     assert hasattr(obj, "__exit__")
diff --git a/projects/tentacles/test/python/test_store_users.py b/projects/tentacles/test/python/test_store_users.py
index c54513b..c091fe0 100644
--- a/projects/tentacles/test/python/test_store_users.py
+++ b/projects/tentacles/test/python/test_store_users.py
@@ -1,39 +1,40 @@
 #!/usr/bin/env python3
 
-from tentacles.db import Db
+from tentacles.store import Store
 
 
-def test_mkuser(db: Db, username_testy, password_testy):
-    res = db.try_create_user(
+def test_mkuser(store: Store, username_testy, password_testy):
+    res = store.try_create_user(
         username=username_testy, email=username_testy, password=password_testy
     )
     assert res
-    assert [(it.id, it.name) for it in db.list_users()] == [(res.id, username_testy)]
+    assert store.list_users() == [(res.id, username_testy)]
 
 
-def test_mksession(db: Db, uid_testy, username_testy, password_testy, login_ttl):
-    assert uid_testy
-    res = db.try_login(username=username_testy, password=password_testy, ttl=login_ttl)
+def test_mksession(store: Store, uid_testy, username_testy, password_testy, login_ttl):
+    res = store.try_login(
+        username=username_testy, password=password_testy, ttl=login_ttl
+    )
     assert res is not None
-    assert [it.id for it in db.list_keys(uid=uid_testy)] == [res.id]
-    assert db.try_key(kid=res.id).user_id == uid_testy
+    assert [it.id for it in store.list_keys(uid=uid_testy)] == [res.id]
+    assert store.try_key(kid=res.id).user_id == uid_testy
 
 
-def test_refresh_key(db: Db, sid_testy, login_ttl):
-    before = db.fetch_key(kid=sid_testy)
-    db.refresh_key(kid=sid_testy, ttl=login_ttl * 2)
-    after = db.fetch_key(kid=sid_testy)
+def test_refresh_key(store: Store, sid_testy, login_ttl):
+    before = store.fetch_key(kid=sid_testy)
+    store.refresh_key(kid=sid_testy, ttl=login_ttl * 2)
+    after = store.fetch_key(kid=sid_testy)
     assert before != after
 
 
-def tets_mkkey(db: Db, sid_testy, uid_testy):
-    assert db.try_key(kid=sid_testy) == uid_testy
-    new_key = db.create_key(kid=sid_testy, ttl=None)
+def tets_mkkey(store: Store, sid_testy, uid_testy):
+    assert store.try_key(kid=sid_testy) == uid_testy
+    new_key = store.create_key(kid=sid_testy, ttl=None)
     assert new_key is not None
-    assert db.try_key(kid=new_key) == uid_testy
+    assert store.try_key(kid=new_key) == uid_testy
 
 
-def test_logout(db: Db, uid_testy, sid_testy):
-    assert db.try_key(kid=sid_testy)
-    db.delete_key(uid=uid_testy, kid=sid_testy)
-    assert not db.try_key(kid=sid_testy)
+def test_logout(store: Store, uid_testy, sid_testy):
+    assert store.try_key(kid=sid_testy)
+    store.delete_key(uid=uid_testy, kid=sid_testy)
+    assert not store.try_key(kid=sid_testy)