From 55149aaa9b415b5db7a829f9c5647629c895bf0b Mon Sep 17 00:00:00 2001
From: Jonathan Jauhari <40555491+jonjau@users.noreply.github.com>
Date: Sun, 24 Aug 2025 21:53:51 +0000
Subject: [PATCH 1/7] Remove unused tfstate file at root
---
terraform.tfstate | 9 ---------
1 file changed, 9 deletions(-)
delete mode 100644 terraform.tfstate
diff --git a/terraform.tfstate b/terraform.tfstate
deleted file mode 100644
index 480e3e3..0000000
--- a/terraform.tfstate
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "version": 4,
- "terraform_version": "1.12.2",
- "serial": 1,
- "lineage": "301c5003-4ed2-60f6-e569-e60abd5a0e9e",
- "outputs": {},
- "resources": [],
- "check_results": null
-}
From e810166f7122ab2431ba66e4bbf209090e9374e7 Mon Sep 17 00:00:00 2001
From: Jonathan Jauhari <40555491+jonjau@users.noreply.github.com>
Date: Sun, 24 Aug 2025 21:54:13 +0000
Subject: [PATCH 2/7] Add basic README starter
---
README.md | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 README.md
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..863a065
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+# Pythia
+
+[](https://github.com/jonjau/pythia/actions/workflows/rust.yml)
+[](https://opensource.org/licenses/MIT)
+
+Pythia is a novel 'state change explorer' tool built with Rust and Prolog.
+
+Run unit tests with database changes tracked in Pythia to see how database records change in the context of each test case.
+
+(need a picture and a logo)
+
+Run locally with `docker` or `podman`, or try out the public demo at [pythia.jonjauhari.com](https://pythia.jonjauhari.com).
+
+(if it is running)
+
+## Features
+
+- Observe how individual records evolve across test runs
+- Web-based UI for exploring changes interactively
+- Anonymous sessions
+- Continuous deployment workflow to AWS Fargate with Terraform
+
+## Usage
+
+## Installation
+
+## Example
+
From dcf8af8a3ab950be146d280a86a38de2e8a1f627 Mon Sep 17 00:00:00 2001
From: Jonathan Jauhari <40555491+jonjau@users.noreply.github.com>
Date: Mon, 25 Aug 2025 11:00:23 +0000
Subject: [PATCH 3/7] Improve placeholder text in add new record type form
---
README.md | 35 +++++++++++++++++++++++++++--------
doc/pythia-icon.png | Bin 0 -> 2973 bytes
templates/how-to-use.html | 2 +-
3 files changed, 28 insertions(+), 9 deletions(-)
create mode 100644 doc/pythia-icon.png
diff --git a/README.md b/README.md
index 863a065..1e02166 100644
--- a/README.md
+++ b/README.md
@@ -3,15 +3,24 @@
[](https://github.com/jonjau/pythia/actions/workflows/rust.yml)
[](https://opensource.org/licenses/MIT)
-Pythia is a novel 'state change explorer' tool built with Rust and Prolog.
+
-Run unit tests with database changes tracked in Pythia to see how database records change in the context of each test case.
+

+
Pythia
+
+
+ A novel 'state change explorer' tool built with Rust and [Scryer Prolog](https://www.scryer.pl/).
+
+
-(need a picture and a logo)
+Run unit tests with database changes tracked in Pythia to help answer questions like:
+- How many unique database records of a certain table does Test T1 change?
+- Which tests cover the mutation of field F from 'ordered', 'processing', then 'completed'?
+- Is state S is reachable from state S' in the context of Test T1 or Test T2?
+- How many database modifications would it take, to take a database record from state S to state S'?
+- If we were to run the functionality covered by Test T1 followed by that of Test T2 on the same database record, what would be the resulting state?
-Run locally with `docker` or `podman`, or try out the public demo at [pythia.jonjauhari.com](https://pythia.jonjauhari.com).
-
-(if it is running)
+Run keeping data local with `docker` or `podman`, or try out the public demo at [pythia.jonjauhari.com](https://pythia.jonjauhari.com) (I don't always keep it running).
## Features
@@ -22,7 +31,17 @@ Run locally with `docker` or `podman`, or try out the public demo at [pythia.jon
## Usage
-## Installation
+Example pictures and text
+
+## How to run
+
+### Prerequisites
+
+- Terraform
+- AWS CLI
+- Docker / Podman
+
+## License
-## Example
+Pythia is currently licensed under the terms of both the MIT license and the Apache License (Version 2.0). See [`LICENSE-MIT`](/LICENSE-MIT) and [`LICENSE-APACHE`](/LICENSE-APACHE) for more details.
diff --git a/doc/pythia-icon.png b/doc/pythia-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..210fe4c654fb04818d229734a387e163c64f158a
GIT binary patch
literal 2973
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 is this?
Pythia is an open-source 'state change
- explorer'. It's a tool to track how
+ explorer'. It's a tool to visualise and search how
records change over time, based on recorded facts
for those record types.
From b2df6456d6f3c324177b636e2ffca76fc5c3327d Mon Sep 17 00:00:00 2001
From: Jonathan Jauhari <40555491+jonjau@users.noreply.github.com>
Date: Mon, 25 Aug 2025 13:09:15 +0000
Subject: [PATCH 4/7] Add screenshots to README
---
README.md | 63 ++++++++++++++++++++++++++++++-----------
doc/facts.png | Bin 0 -> 88780 bytes
doc/pythia-icon.png | Bin 2973 -> 0 bytes
doc/record-types.png | Bin 0 -> 94759 bytes
doc/sessions.png | Bin 0 -> 36740 bytes
doc/state-change-1.png | Bin 0 -> 156655 bytes
doc/state-change-2.png | Bin 0 -> 116911 bytes
7 files changed, 46 insertions(+), 17 deletions(-)
create mode 100644 doc/facts.png
delete mode 100644 doc/pythia-icon.png
create mode 100644 doc/record-types.png
create mode 100644 doc/sessions.png
create mode 100644 doc/state-change-1.png
create mode 100644 doc/state-change-2.png
diff --git a/README.md b/README.md
index 1e02166..1dbded5 100644
--- a/README.md
+++ b/README.md
@@ -3,43 +3,72 @@
[](https://github.com/jonjau/pythia/actions/workflows/rust.yml)
[](https://opensource.org/licenses/MIT)
-
-
-

-
Pythia
-
-
- A novel 'state change explorer' tool built with Rust and [Scryer Prolog](https://www.scryer.pl/).
-
-
+Pythia is a novel 'state change explorer' tool built with Rust and [Scryer Prolog](https://www.scryer.pl/).
Run unit tests with database changes tracked in Pythia to help answer questions like:
- How many unique database records of a certain table does Test T1 change?
-- Which tests cover the mutation of field F from 'ordered', 'processing', then 'completed'?
+- Which tests cover the mutation of field F from 'ordered', 'dispatched', then 'delivered'?
- Is state S is reachable from state S' in the context of Test T1 or Test T2?
+- If field F changes, do any other fields tend to change with it?
- How many database modifications would it take, to take a database record from state S to state S'?
- If we were to run the functionality covered by Test T1 followed by that of Test T2 on the same database record, what would be the resulting state?
-Run keeping data local with `docker` or `podman`, or try out the public demo at [pythia.jonjauhari.com](https://pythia.jonjauhari.com) (I don't always keep it running).
+Run completely locally with `docker` or `podman`, or try out the public demo at [pythia.jonjauhari.com](https://pythia.jonjauhari.com) (I don't always keep it running).
## Features
- Observe how individual records evolve across test runs
-- Web-based UI for exploring changes interactively
-- Anonymous sessions
-- Continuous deployment workflow to AWS Fargate with Terraform
+- Web-based UI for exploring changes interactively with HTMX and TailwindCSS
+- Anonymous sessions with cookies,
+- Continuous deployment workflow to AWS (Fargate) with Terraform
## Usage
-Example pictures and text
+1. Start a session:
+
+
+
+2. Add record types (either via web UI or the REST API):
+
+
+
+3. Add facts for the records (either via the web UI or the REST API):
+
+
+
+4. Calculate state change paths!
+
+
+
+
+There's a few things we can loosely infer:
+- `Test_FailOrder` tests 2 unique 'order' records in total.
+- Both tests cover the mutation of `Status` from 'ordered' to 'dispatched'.
+- Starting from the `Status` of 'ordered' we can reach the `Status` of 'cancelled' or 'delivered'.
+- when the `Status` changes to 'dispatched', the `DispatchDate` is set to some date, likewise for 'delivered' and `DeliveryDate`.
+- It takes 2 steps to get from `Status` of 'ordered' to 'delivered'.
+- We could probably cancel 'Ord2' before it goes to the 'delivered' `Status`.
## How to run
-### Prerequisites
+### Run locally with Docker/Podman
+
+```bash
+docker compose up
+```
+
+Pythia will be listening on port 3000
+
+### Run locally without Docker/Podman
+
+explain environment variables
+
+### Run on AWS
+
+Ensure you have authenticated with the AWS CLI
- Terraform
- AWS CLI
-- Docker / Podman
## License
diff --git a/doc/facts.png b/doc/facts.png
new file mode 100644
index 0000000000000000000000000000000000000000..24646e9dc4d5e02288ba0ae6528a8677c09e6a33
GIT binary patch
literal 88780
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