diff --git a/site/conjecture.html b/site/conjecture.html index 03e688d..c1c5a37 100644 --- a/site/conjecture.html +++ b/site/conjecture.html @@ -62,8 +62,33 @@ .metric .v { font-family:'Space Mono',monospace; font-size:1.4rem; font-weight:700; display:block; } .metric .k { font-size:.78rem; text-transform:uppercase; letter-spacing:.04em; } .frontier { margin:2rem 0 0; border: var(--line); background: var(--ink); color: var(--paper); - padding:1rem 1.2rem; font-family:'Space Mono',monospace; font-size:.82rem; overflow-x:auto; } - .frontier .k { color: var(--yellow); text-transform:uppercase; font-size:.7rem; display:block; margin-bottom:.4rem; } + padding:1rem 1.2rem; font-size:.82rem; } + .frontier .k { color: var(--yellow); text-transform:uppercase; font-size:.7rem; display:block; + font-family:'Space Mono',monospace; letter-spacing:.05em; } + .frontier .khead { display:flex; align-items:baseline; justify-content:space-between; gap:1rem; + margin-bottom:.7rem; } + /* The compacted working set is free-form JSON an agent wrote, so the keys are + unknowable — render the STRUCTURE (keys as labels, values as prose) rather + than dumping stringify output. The old version passed indent-1 JSON through + without a
, so every newline collapsed and the whole state arrived as
+ one unbroken wall of monospace. */
+ .frontier .fk { color: var(--yellow); font-family:'Space Mono',monospace; font-size:.7rem;
+ text-transform:uppercase; letter-spacing:.04em; margin:.9rem 0 .2rem;
+ overflow-wrap:anywhere; }
+ .frontier .fk:first-child { margin-top:0; }
+ .frontier .fk--sub { font-size:.63rem; opacity:.75; margin-top:.6rem; }
+ .frontier .fv { font-weight:300; line-height:1.5; overflow-wrap:anywhere;
+ white-space:pre-wrap; max-width:70ch; }
+ /* Scalars keep the terminal register; long prose gets the readable face. */
+ .frontier .fv--scalar { font-family:'Space Mono',monospace; font-size:.78rem; opacity:.9; }
+ .frontier .fnest { border-left:2px solid #f3c20a55; padding-left:.8rem; margin-top:.3rem; }
+ .frontier .fempty { opacity:.55; font-style:italic; }
+ .frontier .raw { display:block; white-space:pre; overflow-x:auto; font-family:'Space Mono',monospace;
+ font-size:.75rem; margin:0; }
+ .frontier .rawbtn { font-family:'Space Mono',monospace; font-size:.62rem; text-transform:uppercase;
+ background:none; color:var(--paper); border:2px solid #fdfaf288; padding:.15rem .45rem;
+ cursor:pointer; opacity:.7; white-space:nowrap; }
+ .frontier .rawbtn:hover { opacity:1; border-color: var(--yellow); color: var(--yellow); }
.feed-head { margin:2.6rem 0 0; }
.feed { list-style:none; margin:.8rem 0 0; padding:0; border-top: var(--line); }
/* flex-wrap + a shrinkable summary keep the nowrap date from overflowing the
@@ -241,8 +266,12 @@
'' + dollars(m.compute_cents) + 'compute donated' +
'';
if (d.state && Object.keys(d.state).length) {
- h += 'Current frontier' +
- esc(JSON.stringify(d.state, null, 1)) + '';
+ h += '' +
+ 'Current frontier' +
+ '' +
+ '' + stateHtml(d.state) + '' +
+ '' + esc(JSON.stringify(d.state, null, 2)) + '
' +
+ '';
}
h += '';
h += '';
@@ -270,6 +299,7 @@
: '' + esc(d.source_ref) + '
';
}
page.innerHTML = h;
+ wireRaw();
maybeAddVideo(slug);
maybeAddTasks(slug);
maybeAddTree(slug);
@@ -405,6 +435,62 @@
});
}
+ /**
+ * Render the compacted working set as structure instead of a JSON dump.
+ *
+ * `state` is free-form — an agent writes it via state_update, so the keys are
+ * whatever the work needed — which is exactly why it has to be rendered
+ * generically: keys become labels, scalars keep the terminal face, and long
+ * prose values get a readable one. Depth is bounded because a cyclic or
+ * pathologically nested state should degrade to raw text, not hang the page.
+ */
+ function stateHtml(v, depth) {
+ depth = depth || 0;
+ if (v === null || v === undefined) return 'null';
+ if (Array.isArray(v)) {
+ if (!v.length) return '(empty)';
+ // Arrays of scalars read better as one comma-joined line than as a
+ // numbered list of one-word rows.
+ var scalars = v.every(function (x) { return x === null || typeof x !== 'object'; });
+ if (scalars) return '' + esc(v.join(', ')) + '';
+ if (depth > 5) return '' + esc(JSON.stringify(v, null, 2)) + '
';
+ return '' + v.map(function (x, i) {
+ return '' + (i + 1) + '' + stateHtml(x, depth + 1);
+ }).join('') + '';
+ }
+ if (typeof v === 'object') {
+ var keys = Object.keys(v);
+ if (!keys.length) return '(empty)';
+ if (depth > 5) return '' + esc(JSON.stringify(v, null, 2)) + '
';
+ // Nested keys are subordinate to their parent, so they read smaller —
+ // the indent rail alone left every level looking equally important.
+ var kc = depth === 0 ? 'fk' : 'fk fk--sub';
+ var body = keys.map(function (k) {
+ return '' + esc(k.replace(/_/g, ' ')) + '' + stateHtml(v[k], depth + 1);
+ }).join('');
+ return depth === 0 ? body : '' + body + '';
+ }
+ // A scalar. Long strings are prose an agent wrote — set them in the reading
+ // face; short ones (ids, numbers, flags) stay monospace.
+ var s = String(v);
+ return '' + esc(s) + '';
+ }
+
+ /** Toggle between the rendered state and the exact JSON behind it. */
+ function wireRaw() {
+ var btn = document.getElementById('cj-raw');
+ if (!btn) return;
+ var pretty = document.getElementById('cj-state');
+ var raw = document.getElementById('cj-state-raw');
+ btn.addEventListener('click', function () {
+ var showingRaw = btn.getAttribute('aria-pressed') === 'true';
+ btn.setAttribute('aria-pressed', String(!showingRaw));
+ btn.textContent = showingRaw ? 'Raw JSON' : 'Formatted';
+ pretty.hidden = !showingRaw;
+ raw.hidden = showingRaw;
+ });
+ }
+
/** One feed row. Shared by the embedded first page and every paged-in row. */
function feedRow(r) {
// The feed is a work ledger, and the badge says only what actually