diff --git a/docs/.vitepress/theme/DecisionTrace.vue b/docs/.vitepress/theme/DecisionTrace.vue
new file mode 100644
index 0000000..10dc224
--- /dev/null
+++ b/docs/.vitepress/theme/DecisionTrace.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+ placement:maria-harbor
+ receipt
+
+
+
+
+
+
worker
+ worker:maria
+
+
+
site
+ site:harbor
+
+
+
actor
+ {{ receipt.actor }}
+
+
+
governedBy
+ {{ receipt.governedBy }}
+
+
+
One date. Two views of the evidence.
+
Was Maria trained on March 2?
+
+
+ At the decision
+
+
+ After the correction
+
+
+
+
trained
+
{{
+ trained
+ }}
+
+ {{
+ corrected
+ ? "The corrected certificate starts March 5. The earlier belief is still in the record."
+ : "Dana saw a certificate starting March 1. That is the evidence her decision used."
+ }}
+
+
+
+
+
+ Explore saved query results from the checked scenario below ↓
+
+
+
diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css
index c3e5e7d..cbfd251 100644
--- a/docs/.vitepress/theme/custom.css
+++ b/docs/.vitepress/theme/custom.css
@@ -114,301 +114,6 @@ body {
font-size: 14px;
}
-.triplex-index .VPHome {
- margin-bottom: 0;
- padding-bottom: 0;
-}
-
-.triplex-index .VPHome > .vp-doc {
- max-width: 1040px;
- padding: 0 32px;
-}
-
-.triplex-home {
- padding: 48px 0 56px;
-}
-
-.triplex-home__intro h1 {
- margin: 0;
- font-size: clamp(2rem, 5vw, 3rem);
- font-weight: 600;
- letter-spacing: -0.04em;
- line-height: 1.15;
-}
-
-.triplex-home__intro .triplex-home__tagline {
- margin: 14px 0 0;
- color: var(--vp-c-text-1);
- font-size: clamp(1.35rem, 3vw, 1.75rem);
- font-weight: 480;
- letter-spacing: -0.025em;
- line-height: 1.35;
-}
-
-.triplex-home__intro .triplex-home__detail {
- max-width: 760px;
- margin: 10px 0 0;
- color: var(--vp-c-text-2);
- font-size: 1.05rem;
- line-height: 1.65;
-}
-
-.triplex-home__actions {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 12px 20px;
- margin-top: 22px;
-}
-
-.triplex-home__actions a {
- display: inline-flex;
- align-items: center;
- font-weight: 520;
- text-decoration: none;
-}
-
-.triplex-home__actions .triplex-home__primary {
- border-radius: 5px;
- background: var(--vp-c-text-1);
- color: var(--vp-c-bg);
- padding: 9px 14px;
-}
-
-.triplex-home__actions .triplex-home__primary:hover {
- background: var(--vp-c-brand-1);
-}
-
-.triplex-home__actions .triplex-home__secondary {
- color: var(--vp-c-text-2);
-}
-
-.triplex-home__actions .triplex-home__secondary:hover {
- color: var(--vp-c-brand-1);
-}
-
-.triplex-home__intro div[class*="language-"] {
- max-width: 560px;
- margin: 24px 0 0;
- border: 1px solid var(--vp-c-divider);
- border-radius: 7px;
-}
-
-.triplex-home__intro .triplex-home__status {
- max-width: 760px;
- margin: 18px 0 0;
- color: var(--vp-c-text-2);
- font-size: 0.85rem;
- line-height: 1.6;
-}
-
-.triplex-home__agents {
- margin-top: 40px;
- padding: 20px 24px;
- border: 1px solid color-mix(in srgb, var(--vp-c-brand-1) 35%, var(--vp-c-divider));
- border-radius: 7px;
- background: var(--vp-c-brand-soft);
-}
-
-.triplex-home__agents h2 {
- margin: 0 0 10px;
- padding: 0;
- border: 0;
- font-size: 1.05rem;
- letter-spacing: -0.01em;
-}
-
-.triplex-home__agents ul {
- margin: 0;
- padding-left: 1.1em;
-}
-
-.triplex-home__agents li {
- margin: 6px 0;
- color: var(--vp-c-text-2);
- font-size: 0.95rem;
- line-height: 1.6;
-}
-
-.triplex-home__agents li strong {
- color: var(--vp-c-text-1);
-}
-
-.triplex-home__section table {
- display: table;
- width: 100%;
- margin: 0;
- font-size: 0.9rem;
-}
-
-.triplex-home__section th {
- white-space: nowrap;
-}
-
-.triplex-home__section div[class*="language-"] + table {
- margin-top: 24px;
-}
-
-.triplex-home__section td,
-.triplex-home__section th {
- vertical-align: top;
-}
-
-.triplex-home__timeline {
- overflow-x: auto;
-}
-
-.triplex-home__timeline table {
- font-size: 0.82rem;
-}
-
-.triplex-home__timeline td:first-child {
- text-align: right;
-}
-
-.triplex-home__timeline td,
-.triplex-home__timeline th {
- padding: 8px 12px;
- white-space: nowrap;
-}
-
-.triplex-home .triplex-home__output-label {
- margin: 18px 0 8px;
- color: var(--vp-c-text-2);
- font-family: var(--vp-font-family-mono);
- font-size: 0.72rem;
- letter-spacing: 0.06em;
- text-transform: uppercase;
-}
-
-.triplex-home .triplex-home__output-label code {
- font-size: inherit;
- text-transform: none;
-}
-
-.triplex-home__link-icon {
- flex: none;
- margin-left: 0.375em;
-}
-
-.triplex-home__section {
- margin-top: 64px;
- padding-top: 32px;
- border-top: 1px solid var(--vp-c-divider);
-}
-
-.triplex-home__section-intro {
- max-width: 760px;
- margin-bottom: 28px;
-}
-
-.triplex-home .triplex-home__eyebrow {
- margin: 0 0 10px;
- color: var(--vp-c-brand-1);
- font-family: var(--vp-font-family-mono);
- font-size: 0.72rem;
- letter-spacing: 0.06em;
- text-transform: uppercase;
-}
-
-.triplex-home__section h2 {
- margin: 0 0 16px;
- padding: 0;
- border: 0;
- font-size: clamp(1.5rem, 3vw, 1.9rem);
- line-height: 1.25;
-}
-
-.triplex-home__section h3 {
- margin: 0 0 10px;
- font-size: 1.1rem;
- line-height: 1.4;
-}
-
-.triplex-home__section p {
- color: var(--vp-c-text-2);
- line-height: 1.7;
-}
-
-.triplex-home__principles {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 24px;
- margin-top: 28px;
-}
-
-.triplex-home__principles > div {
- padding: 20px;
- border: 1px solid var(--vp-c-divider);
- border-radius: 7px;
- background: var(--vp-c-bg-elv);
-}
-
-.triplex-home__principles p {
- margin: 0;
- font-size: 0.95rem;
-}
-
-.triplex-home .triplex-home__fit {
- margin: 24px 0 0;
- font-size: 0.95rem;
-}
-
-.triplex-home__example {
- margin-top: 36px;
-}
-
-.triplex-home__example + .triplex-home__example {
- padding-top: 36px;
- border-top: 1px solid var(--vp-c-divider);
-}
-
-.triplex-home__example-description {
- max-width: 760px;
- margin-bottom: 20px;
-}
-
-.triplex-home__example-description p {
- margin: 0 0 12px;
- font-size: 0.95rem;
-}
-
-.triplex-home__example-description a {
- display: inline-flex;
- align-items: center;
- font-size: 0.95rem;
-}
-
-.triplex-home__snippet {
- min-width: 0;
-}
-
-.triplex-home__snippet div[class*="language-"],
-.triplex-home__section > div[class*="language-"] {
- margin: 0;
- border: 1px solid var(--vp-c-divider);
- border-radius: 7px;
- box-shadow: none;
-}
-
-.triplex-home__guides {
- display: flex;
- flex-wrap: wrap;
- gap: 16px 32px;
- margin-top: 32px;
- font-size: 0.95rem;
-}
-
-.triplex-home__guides a {
- display: inline-flex;
- align-items: center;
-}
-
-.triplex-home a:focus-visible {
- outline: 2px solid var(--vp-c-brand-1);
- outline-offset: 4px;
-}
-
.vp-doc:not(.triplex-home) h1 {
letter-spacing: -0.045em;
}
@@ -416,30 +121,3 @@ body {
.vp-doc:not(.triplex-home) h2 {
letter-spacing: -0.025em;
}
-
-@media (max-width: 640px) {
- .triplex-index .VPHome > .vp-doc {
- padding: 0 24px;
- }
-
- .triplex-home {
- padding: 36px 0 44px;
- }
-
- .triplex-home__section {
- margin-top: 40px;
- padding-top: 28px;
- }
-}
-
-@media (max-width: 800px) {
- .triplex-home__section table {
- display: block;
- overflow-x: auto;
- }
-
- .triplex-home__principles {
- grid-template-columns: 1fr;
- gap: 20px;
- }
-}
diff --git a/docs/.vitepress/theme/home.css b/docs/.vitepress/theme/home.css
new file mode 100644
index 0000000..b68d49b
--- /dev/null
+++ b/docs/.vitepress/theme/home.css
@@ -0,0 +1,752 @@
+/* Blueprint paper, stamped type, and inspectable evidence: Triplex's place
+ in the WorldVM family. These styles belong only to the public homepage. */
+.triplex-index {
+ --vp-c-bg: #f6f8fb;
+ --vp-c-bg-elv: #fff;
+ --vp-c-text-1: #17202b;
+ --vp-c-text-2: #596574;
+ --vp-c-divider: #d9e1eb;
+ --home-accent: #3457d5;
+ --home-stamp: #1c368d;
+ --home-brand: #a7b5ff;
+ --home-grid: rgb(73 103 163 / 9%);
+ --home-shadow: #17202b;
+}
+.dark .triplex-index {
+ --vp-c-bg: #0d121c;
+ --vp-c-bg-elv: #141d2b;
+ --vp-c-text-1: #e8edf6;
+ --vp-c-text-2: #a7b3c7;
+ --vp-c-divider: #29354b;
+ --home-accent: #a7b5ff;
+ --home-stamp: #5974d1;
+ --home-grid: rgb(132 164 250 / 7%);
+ --home-shadow: #40516f;
+}
+.triplex-index .VPHome {
+ margin-bottom: 0;
+ padding-bottom: 0;
+}
+.triplex-index .VPHome > .vp-doc {
+ max-width: 1280px;
+ padding: 0 48px;
+}
+.triplex-home {
+ padding-bottom: 48px;
+}
+.triplex-home h1,
+.triplex-home h2,
+.triplex-home h3 {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ color: var(--vp-c-text-1);
+}
+.triplex-home p {
+ color: var(--vp-c-text-2);
+ line-height: 1.7;
+}
+.triplex-home .triplex-home__eyebrow {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin: 0 0 16px;
+ font: 400 11px/1.6 var(--vp-font-family-mono);
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ color: var(--home-accent);
+}
+.triplex-home__dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: #23966b;
+ box-shadow: 0 0 0 4px rgb(35 150 107 / 12%);
+ flex: none;
+}
+.triplex-home__intro {
+ position: relative;
+ display: grid;
+ grid-template-columns: 1.06fr 1fr;
+ align-items: center;
+ gap: 56px;
+ padding: 72px 0 64px;
+}
+.triplex-home__intro::before {
+ content: "";
+ position: absolute;
+ inset: 0 -48px -32px;
+ pointer-events: none;
+ background-image:
+ linear-gradient(to right, var(--home-grid) 1px, transparent 1px),
+ linear-gradient(to bottom, var(--home-grid) 1px, transparent 1px);
+ background-size: 32px 32px;
+ mask-image: radial-gradient(ellipse at 50% 35%, #000 30%, transparent 75%);
+}
+.triplex-home__intro > * {
+ position: relative;
+ min-width: 0;
+}
+.triplex-home__wordmark {
+ margin: 12px 0 30px;
+ color: var(--home-brand);
+ font: 800 clamp(76px, 8.8vw, 116px)/0.95 var(--vp-font-family-mono);
+ letter-spacing: -0.09em;
+ -webkit-text-stroke: 1.5px var(--home-stamp);
+ text-shadow: 4px 4px 0 var(--home-stamp);
+}
+.triplex-home__wordmark span {
+ color: var(--home-stamp);
+ text-shadow: none;
+}
+.triplex-home__intro h1 {
+ max-width: 540px;
+ font-size: clamp(36px, 4vw, 52px);
+ font-weight: 650;
+ letter-spacing: -0.045em;
+ line-height: 1.06;
+}
+.triplex-home__intro .triplex-home__tagline {
+ max-width: 450px;
+ margin: 22px 0 0;
+ font-size: 21px;
+ line-height: 1.45;
+ color: var(--vp-c-text-1);
+}
+.triplex-home__intro .triplex-home__detail {
+ margin-top: 16px;
+ font-size: 16px;
+}
+.triplex-home__detail strong {
+ color: var(--vp-c-text-1);
+}
+.triplex-home__actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ margin-top: 28px;
+}
+.triplex-home__actions a {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ min-height: 44px;
+ padding: 9px 16px;
+ border: 1.5px solid var(--vp-c-text-1);
+ border-radius: 8px;
+ background: var(--vp-c-bg-elv);
+ color: var(--vp-c-text-1);
+ box-shadow: 4px 4px 0 var(--home-shadow);
+ font-size: 14px;
+ font-weight: 600;
+ text-decoration: none;
+ transition:
+ transform 0.15s,
+ box-shadow 0.15s;
+}
+.triplex-home__actions .triplex-home__primary {
+ background: var(--vp-c-text-1);
+ color: var(--vp-c-bg);
+ box-shadow: 4px 4px 0 var(--home-brand);
+}
+.triplex-home__actions a:hover {
+ transform: translate(-1px, -1px);
+ box-shadow: 5px 5px 0 var(--home-accent);
+}
+.triplex-home__actions a:active {
+ transform: translate(3px, 3px);
+ box-shadow: 1px 1px 0 var(--home-accent);
+}
+.triplex-home__intro .triplex-home__status {
+ margin-top: 24px;
+ font-size: 12px;
+ line-height: 1.9;
+}
+.decision-trace {
+ margin: 0;
+ font-family: var(--vp-font-family-mono);
+}
+.decision-trace__bar,
+.decision-trace__body {
+ background: #10182a;
+ color: #d9e2f5;
+}
+.decision-trace__bar {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ padding: 16px 20px;
+ border: 1.5px solid #263654;
+ border-radius: 12px 12px 0 0;
+ background: #182238;
+ font-size: 10px;
+ box-shadow: 7px 7px 0 var(--home-brand);
+}
+.decision-trace__dots {
+ display: flex;
+ gap: 5px;
+}
+.decision-trace__dots i {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: #64728a;
+}
+.decision-trace__dots i:first-child {
+ background: #f18487;
+}
+.decision-trace__dots i:nth-child(2) {
+ background: #edc379;
+}
+.decision-trace__dots i:last-child {
+ background: #7ebf9f;
+}
+.decision-trace__badge {
+ margin-left: auto;
+ color: #a7b5ff;
+}
+.decision-trace__body {
+ padding: 28px;
+ border: 1.5px solid #263654;
+ border-top: 0;
+ border-radius: 0 0 12px 12px;
+ box-shadow: 7px 7px 0 var(--home-brand);
+}
+.triplex-home .decision-trace__comment {
+ margin: 0 0 20px;
+ color: #8192b3;
+ font-size: 12px;
+}
+.decision-trace__fields {
+ margin: 0;
+ font-size: 13px;
+}
+.decision-trace__fields > div {
+ display: grid;
+ grid-template-columns: 122px 1fr;
+ gap: 10px;
+ margin: 9px 0;
+}
+.decision-trace__fields dt {
+ color: #91a4c5;
+}
+.decision-trace__fields dd {
+ margin: 0;
+ color: #93dcc0;
+}
+.decision-trace__fields .decision-trace__violet {
+ color: #b6a5ff;
+}
+.decision-trace__divider {
+ margin: 25px 0 18px;
+ padding-top: 18px;
+ border-top: 1px dashed #35425c;
+ color: #8192b3;
+ font-size: 10px;
+}
+.triplex-home .decision-trace__question {
+ color: #e6ecf8;
+ margin: 0 0 16px;
+ font-family: var(--vp-font-family-base);
+ font-size: 19px;
+ font-weight: 500;
+}
+.decision-trace__controls {
+ display: flex;
+ gap: 4px;
+ padding: 4px;
+ border: 1px solid #35425c;
+ border-radius: 6px;
+}
+.decision-trace__controls button {
+ flex: 1;
+ padding: 8px 4px;
+ color: #a4b3cf;
+ background: transparent;
+ border-radius: 3px;
+ font: inherit;
+ font-size: 10px;
+ cursor: pointer;
+}
+.decision-trace__controls button:hover {
+ color: #fff;
+ background: #26334d;
+}
+.decision-trace__controls button[aria-pressed="true"] {
+ color: #eef2ff;
+ background: #34476f;
+}
+.decision-trace__result {
+ display: grid;
+ grid-template-columns: 1fr auto;
+ padding: 20px 0 0;
+ min-height: 116px;
+}
+.decision-trace__result-key {
+ font-size: 13px;
+ color: #91a4c5;
+}
+.decision-trace__result strong {
+ font-size: 20px;
+}
+.decision-trace__yes {
+ color: #93dcc0;
+}
+.decision-trace__no {
+ color: #f6ae98;
+}
+.triplex-home .decision-trace__result p {
+ grid-column: 1 / -1;
+ margin: 9px 0 0;
+ color: #a4b3cf;
+ font-size: 11px;
+ line-height: 1.7;
+}
+.triplex-home .decision-trace__footer {
+ margin: 18px 0 0;
+ font-size: 10px;
+ color: #8192b3;
+}
+.decision-trace__footer span {
+ color: #a7b5ff;
+}
+.decision-trace figcaption {
+ margin: 18px 0 0;
+ font-size: 10px;
+ color: var(--vp-c-text-2);
+ text-align: right;
+}
+.decision-trace figcaption a {
+ text-decoration: none;
+}
+.triplex-home__install {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ padding: 20px 0;
+ border-top: 1px solid var(--vp-c-divider);
+}
+.triplex-home__install .triplex-home__eyebrow {
+ margin: 0;
+ color: var(--vp-c-text-2);
+ font-size: 10px;
+ flex: none;
+}
+.triplex-home__install div[class*="language-"] {
+ flex: 1;
+ min-width: 0;
+ margin: 0;
+ border: 1px solid #263654;
+ border-radius: 6px;
+}
+.triplex-home__install div[class*="language-"] pre {
+ padding: 12px 0;
+}
+.triplex-home__install div[class*="language-"] code {
+ padding: 0 18px;
+ font-size: 11px;
+}
+.triplex-home__install-note {
+ font-size: 11px;
+ color: var(--vp-c-text-2);
+}
+.triplex-home__strip {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ border-block: 1px solid var(--vp-c-divider);
+}
+.triplex-home__strip a {
+ display: grid;
+ grid-template-columns: 48px 1fr;
+ gap: 3px 16px;
+ padding: 26px 20px;
+ text-decoration: none;
+ color: var(--vp-c-text-1);
+}
+.triplex-home__strip a + a {
+ border-left: 1px solid var(--vp-c-divider);
+}
+.triplex-home__strip-symbol {
+ grid-row: span 2;
+ align-self: center;
+ color: var(--home-accent);
+ font: 500 24px var(--vp-font-family-mono);
+}
+.triplex-home__strip strong {
+ font-size: 16px;
+}
+.triplex-home__strip a > span:last-child {
+ font-size: 12px;
+ color: var(--vp-c-text-2);
+}
+.triplex-home__strip a:hover {
+ background: var(--vp-c-bg-elv);
+}
+.triplex-home__agents {
+ display: grid;
+ grid-template-columns: 240px 1fr;
+ gap: 24px;
+ padding: 24px 0;
+ border-bottom: 1px solid var(--vp-c-divider);
+}
+.triplex-home__agents h2 {
+ font: 500 12px/1.7 var(--vp-font-family-mono);
+}
+.triplex-home__agents p {
+ margin: 0;
+ font-size: 13px;
+}
+.triplex-home__section {
+ margin-top: 72px;
+ padding-top: 36px;
+ border-top: 1px solid var(--vp-c-divider);
+}
+.triplex-home__agents + .triplex-home__section {
+ border: 0;
+ padding-top: 0;
+}
+.triplex-home__section-intro {
+ max-width: 780px;
+ margin-bottom: 32px;
+}
+.triplex-home__section h2 {
+ font-size: clamp(28px, 3.4vw, 42px);
+ font-weight: 650;
+ letter-spacing: -0.035em;
+ line-height: 1.12;
+}
+.triplex-home__section h3 {
+ font-size: 24px;
+ font-weight: 550;
+ letter-spacing: -0.025em;
+ line-height: 1.25;
+}
+.triplex-home__section-intro > p:not(.triplex-home__eyebrow) {
+ margin: 18px 0 0;
+ font-size: 16px;
+}
+.triplex-home__section table {
+ display: table;
+ width: 100%;
+ margin: 0;
+ font-size: 13px;
+}
+.triplex-home__section th {
+ font: 500 11px/1.6 var(--vp-font-family-mono);
+ text-align: left;
+ background: var(--vp-c-bg-alt);
+}
+.triplex-home__section th,
+.triplex-home__section td {
+ padding: 14px 18px;
+ border-color: var(--vp-c-divider);
+ vertical-align: top;
+}
+.triplex-home__section tr:nth-child(2n) {
+ background: transparent;
+}
+.triplex-home__timeline {
+ overflow-x: auto;
+ border: 1px solid var(--vp-c-divider);
+ border-radius: 8px;
+}
+.triplex-home__timeline table {
+ font-size: 12px;
+}
+.triplex-home__timeline th,
+.triplex-home__timeline td {
+ white-space: nowrap;
+ padding: 10px 14px;
+}
+.triplex-home__timeline td:first-child {
+ text-align: right;
+}
+.triplex-home .triplex-home__fit {
+ margin: 24px 0 0;
+ font-size: 15px;
+}
+.triplex-home__example {
+ display: grid;
+ grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
+ gap: 44px;
+ margin-top: 40px;
+}
+.triplex-home__example + .triplex-home__example {
+ padding-top: 48px;
+ border-top: 1px solid var(--vp-c-divider);
+}
+.triplex-home__example-description p {
+ margin: 16px 0;
+ font-size: 15px;
+}
+.triplex-home__example-description a {
+ display: inline-flex;
+ align-items: center;
+ font-size: 13px;
+}
+.triplex-home__snippet {
+ min-width: 0;
+}
+.triplex-home__snippet div[class*="language-"],
+.triplex-home__section > div[class*="language-"] {
+ margin: 0;
+ border: 1.5px solid #263654;
+ border-radius: 9px;
+ box-shadow: 5px 5px 0 var(--home-brand);
+}
+.triplex-home__snippet div[class*="language-"] code {
+ font-size: 11px;
+}
+.triplex-home .triplex-home__output-label {
+ margin: 24px 0 10px;
+ font: 400 10px/1.6 var(--vp-font-family-mono);
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+.triplex-home__output-label code {
+ font-size: inherit;
+ text-transform: none;
+}
+.triplex-home__link-icon {
+ flex: none;
+ margin-left: 0.375em;
+}
+.triplex-home__section > div[class*="language-"] + table {
+ margin-top: 28px;
+}
+.triplex-home__principles {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 24px;
+ margin-top: 32px;
+}
+.triplex-home__principles > div {
+ padding: 24px;
+ border: 1px solid var(--vp-c-divider);
+ border-top: 3px solid var(--home-accent);
+ border-radius: 4px;
+ background: var(--vp-c-bg-elv);
+}
+.triplex-home__principles h3 {
+ font-size: 19px;
+}
+.triplex-home__principles p {
+ margin-bottom: 0;
+ font-size: 14px;
+}
+.triplex-home__family {
+ margin-top: 80px;
+ padding: 40px;
+ background: #f7f4ec;
+ border: 1px solid #ddd5c6;
+ border-radius: 12px;
+}
+.triplex-home__family .triplex-home__eyebrow {
+ color: #726553;
+}
+.triplex-home__family-head {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 40px;
+ align-items: center;
+}
+.triplex-home__family h2 {
+ color: #302b23;
+ font-size: 38px;
+ font-weight: 650;
+ letter-spacing: -0.035em;
+ line-height: 1.1;
+}
+.triplex-home__family-head p {
+ color: #726553;
+ margin: 0;
+ font-size: 14px;
+}
+.triplex-home__family-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 16px;
+ margin-top: 28px;
+}
+.triplex-home__family-grid a {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding: 22px;
+ border: 1px solid #ddd5c6;
+ border-radius: 8px;
+ background: #fffdf7;
+ color: #302b23;
+ text-decoration: none;
+}
+.triplex-home__family-grid a:hover {
+ border-color: #726553;
+}
+.triplex-home__swatch {
+ width: 28px;
+ height: 28px;
+ border: 1px solid rgb(48 43 35 / 15%);
+ border-radius: 5px;
+ background: var(--project-color);
+}
+.triplex-home__family-grid strong {
+ font-size: 18px;
+}
+.triplex-home__family-grid a > span:last-child {
+ font-size: 13px;
+ color: #726553;
+ line-height: 1.6;
+}
+.triplex-home .triplex-home__family-link {
+ display: inline-block;
+ margin-top: 24px;
+ font-size: 14px;
+ font-weight: 600;
+ color: #302b23;
+}
+.triplex-home__guides {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px 28px;
+ margin-top: 36px;
+ font-size: 13px;
+}
+.triplex-home__guides a {
+ display: inline-flex;
+ align-items: center;
+}
+.triplex-home :is(a, button):focus-visible {
+ outline: 3px solid var(--home-accent);
+ outline-offset: 4px;
+}
+.triplex-home .decision-trace button:focus-visible {
+ outline-color: #a7b5ff;
+}
+@media (max-width: 1000px) {
+ .triplex-home__intro {
+ gap: 32px;
+ }
+ .triplex-home__install {
+ flex-wrap: wrap;
+ }
+ .triplex-home__install-note {
+ width: 100%;
+ }
+ .triplex-home__strip a {
+ grid-template-columns: 1fr;
+ }
+ .triplex-home__strip-symbol {
+ grid-row: auto;
+ }
+ .triplex-home__example {
+ grid-template-columns: 1fr;
+ gap: 20px;
+ }
+ .triplex-home__example-description {
+ max-width: 780px;
+ }
+}
+@media (max-width: 800px) {
+ .triplex-index .VPHome > .vp-doc {
+ padding: 0 24px;
+ }
+ .triplex-home__intro {
+ grid-template-columns: 1fr;
+ padding: 44px 0;
+ gap: 40px;
+ }
+ .triplex-home__intro::before {
+ inset-inline: -24px;
+ }
+ .triplex-home__wordmark {
+ font-size: 90px;
+ }
+ .triplex-home__hero-copy {
+ max-width: 560px;
+ }
+ .decision-trace {
+ width: 100%;
+ max-width: 560px;
+ }
+ .triplex-home__agents {
+ grid-template-columns: 1fr;
+ gap: 10px;
+ }
+ .triplex-home__section table {
+ display: block;
+ overflow-x: auto;
+ }
+ .triplex-home__principles,
+ .triplex-home__family-head {
+ grid-template-columns: 1fr;
+ gap: 20px;
+ }
+ .triplex-home__family {
+ padding: 28px;
+ }
+ .triplex-home__family-grid {
+ grid-template-columns: 1fr;
+ }
+}
+@media (max-width: 480px) {
+ .triplex-home__wordmark {
+ font-size: 76px;
+ }
+ .triplex-home__intro .triplex-home__eyebrow {
+ font-size: 9px;
+ }
+ .triplex-home__strip {
+ grid-template-columns: 1fr;
+ }
+ .triplex-home__strip a {
+ grid-template-columns: 48px 1fr;
+ padding: 18px 12px;
+ }
+ .triplex-home__strip-symbol {
+ grid-row: span 2;
+ }
+ .triplex-home__strip a + a {
+ border-left: 0;
+ border-top: 1px solid var(--vp-c-divider);
+ }
+ .triplex-home__install {
+ gap: 12px;
+ }
+ .triplex-home__install .triplex-home__eyebrow {
+ width: 100%;
+ }
+ .decision-trace__body {
+ padding: 22px;
+ }
+ .decision-trace__bar {
+ padding: 14px;
+ gap: 9px;
+ font-size: 9px;
+ }
+ .decision-trace__fields {
+ font-size: 11px;
+ }
+ .decision-trace__fields > div {
+ grid-template-columns: 95px 1fr;
+ }
+ .decision-trace__controls button {
+ font-size: 9px;
+ }
+ .triplex-home__section {
+ margin-top: 48px;
+ padding-top: 28px;
+ }
+ .triplex-home__family {
+ padding: 24px;
+ margin-top: 48px;
+ }
+ .triplex-home__family h2 {
+ font-size: 32px;
+ }
+}
+@media (prefers-reduced-motion: reduce) {
+ .triplex-home__actions a {
+ transition: none;
+ }
+}
diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts
index e22329e..18ad500 100644
--- a/docs/.vitepress/theme/index.ts
+++ b/docs/.vitepress/theme/index.ts
@@ -5,8 +5,10 @@ import DefaultTheme from "vitepress/theme-without-fonts";
import { defineComponent, h } from "vue";
import "./custom.css";
+import "./home.css";
import Playground from "./Playground.vue";
import TriplexExplorer from "./TriplexExplorer.vue";
+import DecisionTrace from "./DecisionTrace.vue";
export default {
extends: DefaultTheme,
@@ -29,6 +31,7 @@ export default {
},
}),
enhanceApp({ app }) {
+ app.component("DecisionTrace", DecisionTrace);
app.component("TriplexPlayground", Playground);
app.component("TriplexExplorer", TriplexExplorer);
},
diff --git a/docs/index.md b/docs/index.md
index f0dd762..151e916 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -11,36 +11,47 @@ pageClass: triplex-index
-Triplex
+
+
An embedded fact database · TypeScript + Effect
+
triplex_
The database that remembers why.
-
An embedded fact database for TypeScript back-office systems.
-
Every write records who made it, which versioned rules governed it, and when it was true. Audit questions and open work become queries instead of investigations.
+
Facts change. Rules change. Your record of what happened shouldn’t.
+
Triplex keeps facts, time, and versioned rules together. Every write records who acted , which rules applied , and when it was true . Audit questions and open work become queries instead of investigations.
+
+
+
Pre-1.0 · MIT licensed · In-memory + SQLite supported PostgreSQL is a production candidate · Current state ↗
+
+
+
+
+
+
Start in your process
```sh
npm install @triplex-build/triplex effect@4.0.0-rc.112
```
-
-
Pre-1.0 · Built on Effect 4 (effect@4.0.0-rc.112; Effect 3 is not compatible) · In-memory and SQLite supported · PostgreSQL is a production candidate · Maturity contract
-
+
+
+t₁ / t₂ Two clocks. What was true. What you knew.
+# Pinned rules. The release behind every decision.
+=> Derived work. What should happen next.
+
-
The problem
+
00 / The missing context
“Why?” is the most expensive question a back-office system gets asked.
An auditor asks: was Maria trained for the Harbor site on the day she started there? In a typical stack, the evidence is spread across systems that never shared an identity model or a clock.
@@ -57,10 +68,10 @@ npm install @triplex-build/triplex effect@4.0.0-rc.112
-
One scenario, start to finish
+
01 / One scenario, start to finish
Maria, the Harbor site, and a certificate that was wrong.
Maria is trained for Harbor from March 1 to June 1 and placed there on March 2 under release hr-2026.1. The rules then change: hr-2026.2 requires a supervisor on every placement. Later, an auditor finds that the certificate actually began on March 5.
-
After the scenario runs, the database’s own journal reads:
+
Every snippet is type-checked. Every output is produced by running this scenario in CI . The database’s own journal reads:
@@ -87,7 +98,7 @@ npm install @triplex-build/triplex effect@4.0.0-rc.112
-
Three questions, three queries
+
02 / Three questions, three queries
Ask what you knew, which rules applied, and what happens next.
Each answer below is the real output of the code beside it.
@@ -157,7 +168,7 @@ npm install @triplex-build/triplex effect@4.0.0-rc.112
-
Derived work
+
03 / Derived work
Stop enqueuing obligations. Reconcile them.
Most back-office bugs come down to a task that should exist but doesn’t, or one that exists but shouldn’t. Event handlers create work one step at a time and drift out of sync with the data. A derivation states what should be true, and reconciliation reports the difference.
@@ -189,7 +200,7 @@ npm install @triplex-build/triplex effect@4.0.0-rc.112
-
Modeling
+
04 / Modeling
From a back-office domain to Triplex primitives.
Most back-office systems are built from the same parts. This is where each part goes.
@@ -211,7 +222,7 @@ npm install @triplex-build/triplex effect@4.0.0-rc.112
-
Deployment
+
05 / Deployment
A library, not another server.
Triplex runs inside your process as Effect layers. Switching storage changes the layer you provide, and the rest of the program stays the same. On PostgreSQL, Triplex can share your application’s transaction, so your own rows, Triplex facts, the journal, and an outbox row commit or roll back together.
@@ -231,7 +242,7 @@ npm install @triplex-build/triplex effect@4.0.0-rc.112
-
Fit
+
06 / Fit
When to use Triplex, and when not to.
@@ -250,6 +261,20 @@ npm install @triplex-build/triplex effect@4.0.0-rc.112
+
+07 / Part of the WorldVM family
+
+
A memory for your world.
+
Small experiments in software you can inspect, explain, and build on. Triplex keeps the facts. These projects explore the language and models around them.
+
+
+Meet the whole family at worldvm.com ↗
+
+
Quickstart
Modeling guide
diff --git a/e2e/docs-home.spec.ts b/e2e/docs-home.spec.ts
index ae04d4f..f37b1f7 100644
--- a/e2e/docs-home.spec.ts
+++ b/e2e/docs-home.spec.ts
@@ -59,6 +59,25 @@ test("home examples remain visible on mobile without page overflow", async ({ pa
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(390);
});
+test("decision receipt preserves its rules while switching recorded knowledge", async ({
+ page,
+}) => {
+ await page.goto("/");
+ const receipt = page.locator(".decision-trace");
+ const original = receipt.getByRole("button", { name: "At the decision", exact: true });
+ const corrected = receipt.getByRole("button", { name: "After the correction", exact: true });
+ await expect(original).toHaveAttribute("aria-pressed", "true");
+ await expect(receipt.locator(".decision-trace__result strong")).toHaveText("true");
+ await corrected.click();
+ await expect(corrected).toHaveAttribute("aria-pressed", "true");
+ await expect(original).toHaveAttribute("aria-pressed", "false");
+ await expect(receipt.locator(".decision-trace__result strong")).toHaveText("false");
+ await expect(receipt).toContainText("The corrected certificate starts March 5.");
+ await expect(receipt.locator(".decision-trace__fields")).toContainText("hr-2026.1");
+ await original.click();
+ await expect(receipt.locator(".decision-trace__result strong")).toHaveText("true");
+});
+
test("agent-readable documentation is served as plain text", async ({ request }) => {
const index = await request.get("/llms.txt");
expect(index.ok()).toBe(true);
diff --git a/e2e/docs-home.spec.ts-snapshots/home-dark.png b/e2e/docs-home.spec.ts-snapshots/home-dark.png
index 40117e5..0b962a0 100644
Binary files a/e2e/docs-home.spec.ts-snapshots/home-dark.png and b/e2e/docs-home.spec.ts-snapshots/home-dark.png differ
diff --git a/e2e/docs-home.spec.ts-snapshots/home-light.png b/e2e/docs-home.spec.ts-snapshots/home-light.png
index c937857..b3e67fb 100644
Binary files a/e2e/docs-home.spec.ts-snapshots/home-light.png and b/e2e/docs-home.spec.ts-snapshots/home-light.png differ