Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions server/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,10 @@ func TestUIScoredFalseSuppressesVerdicts(t *testing.T) {
t.Error("loss curve is not gated on d.scored; it would render when unscored")
}

// The table function must accept a scored parameter.
if !strings.Contains(page, "function table(rungs, scored)") {
// The table function must accept a scored parameter and the corridor's
// dependencies (so an unpriced DERIVATIVE rung can name what it routes
// through without overflowing the row).
if !strings.Contains(page, "function table(rungs, scored, depends)") {
t.Error("table() does not accept a scored parameter")
}

Expand Down
92 changes: 77 additions & 15 deletions server/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,26 @@
background: var(--panel); border: 1px solid var(--border);
border-radius: 10px; padding: 1.15rem 1.25rem; margin-bottom: 1.25rem;
}
.integrity-card { display: grid; grid-template-columns: auto 1fr; gap: .75rem 1rem; align-items: start; margin-bottom: .35rem; }
.badge {
display: inline-block; font: 600 .72rem/1 var(--mono); letter-spacing: .06em;
padding: .4rem .6rem; border-radius: 5px; border: 1px solid currentColor;
text-transform: uppercase;
display: inline-flex; align-items: center; gap: .45rem; width: fit-content;
font: 700 .78rem/1 var(--mono); letter-spacing: .06em;
padding: .55rem .7rem; border-radius: 7px; border: 2px solid currentColor;
text-transform: uppercase; white-space: nowrap;
}
.b-direct { color: var(--muted); }
.b-derivative { color: var(--warn); }
.b-nomarket { color: var(--bad); }
.badge::before { font-size: 1rem; line-height: 1; }
.b-direct { color: var(--ok); background: var(--ok-soft); }
.b-direct::before { content: "◆"; }
.b-derivative { color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, var(--panel)); }
.b-derivative::before { content: "↪"; }
.b-nomarket { color: var(--bad); background: var(--bad-soft); }
.b-nomarket::before { content: "∅"; }
.integrity-copy { min-width: 0; }
.integrity-title { font-weight: 700; margin: 0; }
.integrity-help { color: var(--muted); font-size: .88rem; margin: .15rem 0 0; }
.integrity-dependency { font-family: var(--mono); font-size: .8rem; margin: .35rem 0 0; color: var(--warn); }
.integrity-card .badge[title] { cursor: help; }
@media (max-width: 520px) { .integrity-card { grid-template-columns: 1fr; gap: .45rem; } }
.finding { font-size: 1.02rem; margin: .85rem 0 0; }
.rec-none {
margin-top: .9rem; padding: .7rem .85rem; border-radius: 6px;
Expand Down Expand Up @@ -136,6 +148,10 @@
.legend-item { display: flex; align-items: center; gap: .45rem; min-width: 0; }
.legend-item span:last-child { font-size: .8rem; }
.case { font-size: .88rem; color: var(--muted); }
.integrity-cell { white-space: nowrap; }
.integrity-cell .badge { font-size: .65rem; padding: .3rem .45rem; border-width: 1px; }
.integrity-cell .badge::before { font-size: .8rem; }
Comment thread
coderabbitai[bot] marked this conversation as resolved.
.integrity-cell .integrity-via { font-family: var(--mono); font-size: .72rem; color: var(--warn); margin-left: .35rem; }
.case strong { color: var(--ink); font-weight: 600; }
svg { width: 100%; height: auto; display: block; }
.axis { fill: var(--muted); font: 10px var(--mono); }
Expand Down Expand Up @@ -234,6 +250,50 @@ <h1>Wayfare</h1>
const badgeClass = (i) =>
i === 'NO-MARKET' ? 'b-nomarket' : i === 'DERIVATIVE' ? 'b-derivative' : 'b-direct';

const integrityInfo = (state, dependsOn = []) => {
if (state === 'NO-MARKET') return {
title: 'No market exists',
help: 'No path exists at the tested size. This is the absence of a price — not a bad price.',
tooltip: 'NO-MARKET means no path exists at all: there is no loss percentage to compute.'
};
if (state === 'DERIVATIVE') {
const via = dependsOn.length ? dependsOn.map(a => a.code || a).join(' and ') : 'another fiat token';
return {
title: 'Depends on an upstream corridor',
help: `Every path routes through ${via}; there is no independent market.`,
dependency: `depends on ${via}`,
tooltip: `DERIVATIVE means every available path traverses another fiat-pegged token, so this corridor inherits its liquidity and failure modes.`
};
}
return {
title: 'Independent market found',
help: 'At least one path reaches the destination without another fiat token in between.',
tooltip: 'DIRECT means an independent market exists: at least one path reaches the destination without routing through another fiat token.'
};
};

function integrityElement(state, dependsOn = '') {
const info = integrityInfo(state, Array.isArray(dependsOn) ? dependsOn : []);
const dependency = info.dependency ? `<p class="integrity-dependency">${esc(info.dependency)}</p>` : '';
return `<div class="integrity-card">
<span class="badge ${badgeClass(state)}" title="${esc(info.tooltip)}" aria-label="${esc(state)}: ${esc(info.tooltip)}">${esc(state)}</span>
<div class="integrity-copy"><p class="integrity-title">${esc(info.title)}</p><p class="integrity-help">${esc(info.help)}</p>${dependency}</div>
</div>`;
}

// Compact form for table cells: the state badge plus a short dependency
// note, with the full explanation kept in the hover tooltip. The headline
// and trend views carry the complete card; inside a nowrap table cell the
// card's description would overflow the row.
function integrityCell(state, dependsOn = []) {
const info = integrityInfo(state, Array.isArray(dependsOn) ? dependsOn : []);
const tip = info.tooltip + (info.dependency ? ' — ' + info.dependency : '');
const dependency = info.dependency
? `<span class="integrity-via">${esc(info.dependency)}</span>` : '';
return `<span class="badge ${badgeClass(state)}" title="${esc(tip)}"
aria-label="${esc(state)}: ${esc(tip)}">${esc(state)}</span>${dependency}`;
}

const verdictClass = (v) => 'v-' + String(v).toLowerCase();

const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
Expand Down Expand Up @@ -269,7 +329,7 @@ <h1>Wayfare</h1>

// Headline: integrity state and the finding, before any numbers.
parts.push(`${provenance}<div class="panel">
<span class="badge ${badgeClass(d.integrity)}">${esc(d.integrity)}</span>
${integrityElement(d.integrity, d.depends_on || [])}
<p class="finding">${esc(d.finding)}</p>
${d.scored ? recommendationBlock(d) : unscoredBlock(d)}
<p class="meta">Reference ${esc(d.reference_pair)} mid
Expand All @@ -282,7 +342,7 @@ <h1>Wayfare</h1>
parts.push(`<div class="panel"><h2>Loss against mid, by size</h2>${curve(priced)}</div>`);
}

parts.push(`<div class="panel"><h2>Measurements</h2><div class="scroll">${table(d.rungs, d.scored)}</div></div>`);
parts.push(`<div class="panel"><h2>Measurements</h2><div class="scroll">${table(d.rungs, d.scored, d.depends_on || [])}</div></div>`);

if (d.scored) parts.push(legend());

Expand Down Expand Up @@ -363,20 +423,24 @@ <h1>Wayfare</h1>
</svg>`;
}

function table(rungs, scored) {
function table(rungs, scored, depends) {
const rows = rungs.map(r => {
if (!r.priced) {
const why = r.error ? esc(r.error)
: r.integrity === 'NO-MARKET' ? 'no path exists at this size'
: 'not priced';
// An unpriced rung still reports the corridor's structural state, so a
// DERIVATIVE rung names what it routes through; the compact cell keeps
// the row from overflowing the table.
const cell = integrityCell(r.integrity, depends);
if (scored) {
return `<tr><td class="num">${esc(r.send_amount)}</td>
<td colspan="4" class="err">${why}</td>
<td>${esc(r.integrity)}</td></tr>`;
<td class="integrity-cell">${cell}</td></tr>`;
}
return `<tr><td class="num">${esc(r.send_amount)}</td>
<td colspan="2" class="err">${why}</td>
<td>${esc(r.integrity)}</td></tr>`;
<td class="integrity-cell">${cell}</td></tr>`;
}
const q = r.quote;
if (scored) {
Expand Down Expand Up @@ -623,7 +687,7 @@ <h2>Trend &mdash; ${esc(d.corridor)}</h2>
const latest = runs[runs.length - 1];
parts.push(`<div class="panel">
<h2>Trend &mdash; ${esc(d.corridor)}</h2>
<span class="badge ${badgeClass(latest.integrity)}">${esc(latest.integrity)}</span>
${integrityElement(latest.integrity, latest.depends_on || [])}
<span class="case">&nbsp; latest of ${runs.length} stored run(s) &middot;
${esc(fmtRunTime(runs[0].recorded_at))} &rarr; ${esc(fmtRunTime(latest.recorded_at))} UTC</span>
<p class="meta">${referenceSummary(runs)}${integritySummary(runs)}</p>
Expand Down Expand Up @@ -830,16 +894,14 @@ <h2>Stored runs</h2>
const rows = runs.slice().reverse().map(r => {
const ref = r.reference || {};
const src = ref.scored_against || ref.source || 'unknown';
const via = (r.depends_on || []).length
? ` <span class="case">via ${esc(r.depends_on.join(', '))}</span>` : '';
const div = ref.divergence_pct
? ` <span class="case">div ${esc(ref.divergence_pct)}%</span>` : '';
return `<tr>
<td class="num">${esc(r.recorded_at)}</td>
<td class="num">${r.seq}</td>
<td><span class="badge ${badgeClass(r.integrity)}">${esc(r.integrity)}</span>${via}</td>
<td class="num">${esc(r.floor_loss_pct)}%</td>
<td class="num">${esc(r.worst_loss_pct)}%</td>
<td class="integrity-cell">${integrityCell(r.integrity, r.depends_on || [])}</td>
<td>${esc(src)}${div}</td>
</tr>`;
}).join('');
Expand Down
Loading