2118 lines
60 KiB
HTML
2118 lines
60 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN" data-theme="dark">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="description" content="Quant OS 公开只读验收面板:按证据展示数据、模型、平台、执行与 G1–G10 的真实完成度。">
|
||
<meta name="color-scheme" content="dark light">
|
||
<meta name="referrer" content="no-referrer">
|
||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'">
|
||
<title>Quant OS · 公开验收控制台</title>
|
||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23101418'/%3E%3Cpath d='M7 8h18v3H7zm0 7h12v3H7zm0 7h18v3H7z' fill='%232FA36B'/%3E%3C/svg%3E">
|
||
<style>
|
||
:root {
|
||
color-scheme: dark;
|
||
--bg: #101418;
|
||
--surface: #151b20;
|
||
--surface-raised: #1b232a;
|
||
--steel: #27313a;
|
||
--steel-soft: #202930;
|
||
--line: #34414a;
|
||
--line-strong: #53616b;
|
||
--ink: #e8ecef;
|
||
--muted: #aab4bb;
|
||
--faint: #7d8b94;
|
||
--verified: #52bf82;
|
||
--implemented: #7e9aab;
|
||
--amber: #d79a2b;
|
||
--fault: #e0645f;
|
||
--focus: #f3c969;
|
||
--link: #83cdb8;
|
||
--shadow: rgba(0, 0, 0, 0.26);
|
||
--sans: "IBM Plex Sans", "Noto Sans SC", sans-serif;
|
||
--mono: "IBM Plex Mono", "Noto Sans SC", monospace;
|
||
--content-width: 1720px;
|
||
}
|
||
|
||
:root[data-theme="light"] {
|
||
color-scheme: light;
|
||
--bg: #f0eee8;
|
||
--surface: #faf9f5;
|
||
--surface-raised: #ffffff;
|
||
--steel: #dce2e2;
|
||
--steel-soft: #e8ecea;
|
||
--line: #c4cece;
|
||
--line-strong: #7d8c8c;
|
||
--ink: #172026;
|
||
--muted: #526169;
|
||
--faint: #58656b;
|
||
--verified: #147a4a;
|
||
--implemented: #496d7e;
|
||
--amber: #92620c;
|
||
--fault: #b33c37;
|
||
--focus: #7f5700;
|
||
--link: #0f6d61;
|
||
--shadow: rgba(20, 30, 34, 0.09);
|
||
}
|
||
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html {
|
||
scroll-behavior: smooth;
|
||
scroll-padding-top: 24px;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
background: var(--bg);
|
||
color: var(--ink);
|
||
font-family: var(--sans);
|
||
font-size: 15px;
|
||
line-height: 1.62;
|
||
text-rendering: optimizeLegibility;
|
||
}
|
||
|
||
a {
|
||
color: var(--link);
|
||
text-decoration-thickness: 1px;
|
||
text-underline-offset: 3px;
|
||
}
|
||
|
||
a:hover {
|
||
text-decoration-thickness: 2px;
|
||
}
|
||
|
||
button,
|
||
input,
|
||
select {
|
||
color: inherit;
|
||
font: inherit;
|
||
}
|
||
|
||
button {
|
||
cursor: pointer;
|
||
}
|
||
|
||
button:focus-visible,
|
||
input:focus-visible,
|
||
select:focus-visible,
|
||
a:focus-visible,
|
||
summary:focus-visible {
|
||
outline: 3px solid var(--focus);
|
||
outline-offset: 3px;
|
||
}
|
||
|
||
.skip-link {
|
||
position: fixed;
|
||
z-index: 100;
|
||
top: 8px;
|
||
left: 8px;
|
||
padding: 10px 14px;
|
||
transform: translateY(-180%);
|
||
border: 1px solid var(--focus);
|
||
background: var(--surface-raised);
|
||
color: var(--ink);
|
||
}
|
||
|
||
.skip-link:focus {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.page-shell {
|
||
width: min(100%, var(--content-width));
|
||
margin: 0 auto;
|
||
padding: 20px 28px 72px;
|
||
}
|
||
|
||
.masthead {
|
||
display: grid;
|
||
grid-template-columns: minmax(230px, 0.78fr) minmax(420px, 1.7fr) auto;
|
||
align-items: stretch;
|
||
border: 1px solid var(--line-strong);
|
||
background: var(--surface);
|
||
box-shadow: 10px 10px 0 var(--shadow);
|
||
}
|
||
|
||
.masthead__brand,
|
||
.masthead__claim,
|
||
.masthead__tools {
|
||
min-width: 0;
|
||
padding: 18px 20px;
|
||
}
|
||
|
||
.masthead__brand {
|
||
border-right: 1px solid var(--line);
|
||
}
|
||
|
||
.masthead__claim {
|
||
border-right: 1px solid var(--line);
|
||
}
|
||
|
||
.eyebrow,
|
||
.section-code,
|
||
.metric__label,
|
||
.rail__label,
|
||
.table-label,
|
||
.status-tag,
|
||
.hash {
|
||
font-family: var(--mono);
|
||
letter-spacing: 0.055em;
|
||
}
|
||
|
||
.eyebrow {
|
||
margin: 0 0 8px;
|
||
color: var(--muted);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.brand-title {
|
||
margin: 0;
|
||
font-size: clamp(24px, 2.4vw, 36px);
|
||
font-weight: 600;
|
||
letter-spacing: -0.035em;
|
||
line-height: 1;
|
||
}
|
||
|
||
.brand-subtitle {
|
||
margin: 8px 0 0;
|
||
color: var(--muted);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.claim-line {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px 14px;
|
||
align-items: center;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.claim-title {
|
||
margin: 0;
|
||
color: var(--fault);
|
||
font-family: var(--mono);
|
||
font-size: clamp(18px, 2vw, 27px);
|
||
font-weight: 600;
|
||
line-height: 1.1;
|
||
}
|
||
|
||
.claim-copy {
|
||
max-width: 900px;
|
||
margin: 0;
|
||
color: var(--muted);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.masthead__tools {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
gap: 14px;
|
||
min-width: 210px;
|
||
}
|
||
|
||
.tool-button {
|
||
display: inline-flex;
|
||
min-height: 44px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
border: 1px solid var(--line-strong);
|
||
border-radius: 2px;
|
||
background: transparent;
|
||
color: var(--ink);
|
||
padding: 8px 12px;
|
||
}
|
||
|
||
.tool-button:hover {
|
||
background: var(--steel-soft);
|
||
}
|
||
|
||
.icon {
|
||
width: 18px;
|
||
height: 18px;
|
||
flex: 0 0 auto;
|
||
fill: none;
|
||
stroke: currentColor;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
stroke-width: 2;
|
||
}
|
||
|
||
.sync-note {
|
||
color: var(--faint);
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.safety-banner {
|
||
display: grid;
|
||
grid-template-columns: auto 1fr auto;
|
||
gap: 12px;
|
||
align-items: center;
|
||
margin-top: 14px;
|
||
border: 1px solid color-mix(in srgb, var(--fault) 74%, var(--line));
|
||
border-left: 5px solid var(--fault);
|
||
background: color-mix(in srgb, var(--fault) 8%, var(--surface));
|
||
padding: 12px 16px;
|
||
}
|
||
|
||
.safety-banner strong {
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
letter-spacing: 0.04em;
|
||
}
|
||
|
||
.safety-banner p {
|
||
margin: 0;
|
||
color: var(--muted);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.snapshot-label {
|
||
color: var(--fault);
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.metrics {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
margin-top: 14px;
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
}
|
||
|
||
.metric {
|
||
min-width: 0;
|
||
padding: 15px 18px;
|
||
border-right: 1px solid var(--line);
|
||
}
|
||
|
||
.metric:last-child {
|
||
border-right: 0;
|
||
}
|
||
|
||
.metric__label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
color: var(--faint);
|
||
font-size: 10px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.metric__value {
|
||
display: block;
|
||
overflow-wrap: anywhere;
|
||
font-family: var(--mono);
|
||
font-size: clamp(18px, 2vw, 27px);
|
||
font-weight: 600;
|
||
line-height: 1.15;
|
||
}
|
||
|
||
.metric__note {
|
||
display: block;
|
||
margin-top: 5px;
|
||
color: var(--muted);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.audit-grid {
|
||
display: grid;
|
||
grid-template-columns: 176px minmax(0, 1fr) 304px;
|
||
gap: 24px;
|
||
align-items: start;
|
||
margin-top: 26px;
|
||
}
|
||
|
||
.rail,
|
||
.blocker-panel {
|
||
position: sticky;
|
||
top: 18px;
|
||
}
|
||
|
||
.rail {
|
||
border-left: 1px solid var(--line-strong);
|
||
}
|
||
|
||
.rail__label {
|
||
display: block;
|
||
padding: 0 0 10px 15px;
|
||
color: var(--faint);
|
||
font-size: 10px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.rail a {
|
||
display: grid;
|
||
grid-template-columns: 24px 1fr;
|
||
min-height: 44px;
|
||
align-items: center;
|
||
border-left: 3px solid transparent;
|
||
color: var(--muted);
|
||
padding: 5px 8px 5px 12px;
|
||
font-size: 13px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.rail a:hover,
|
||
.rail a[aria-current="true"] {
|
||
border-left-color: var(--verified);
|
||
background: var(--steel-soft);
|
||
color: var(--ink);
|
||
}
|
||
|
||
.rail__index {
|
||
color: var(--faint);
|
||
font-family: var(--mono);
|
||
font-size: 10px;
|
||
}
|
||
|
||
.main-content {
|
||
min-width: 0;
|
||
}
|
||
|
||
.audit-section {
|
||
scroll-margin-top: 20px;
|
||
margin-bottom: 48px;
|
||
}
|
||
|
||
.section-header {
|
||
display: grid;
|
||
grid-template-columns: 66px minmax(0, 1fr);
|
||
gap: 16px;
|
||
align-items: start;
|
||
margin-bottom: 16px;
|
||
border-top: 2px solid var(--line-strong);
|
||
padding-top: 13px;
|
||
}
|
||
|
||
.section-code {
|
||
color: var(--verified);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.section-title {
|
||
margin: 0;
|
||
font-size: clamp(20px, 2vw, 27px);
|
||
font-weight: 600;
|
||
letter-spacing: -0.02em;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.section-intro {
|
||
max-width: 860px;
|
||
margin: 6px 0 0;
|
||
color: var(--muted);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.loading-state,
|
||
.error-state,
|
||
.empty-state {
|
||
border: 1px dashed var(--line-strong);
|
||
background: var(--surface);
|
||
padding: 24px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.error-state {
|
||
border-color: var(--fault);
|
||
color: var(--fault);
|
||
}
|
||
|
||
.overview-board {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1.2fr) minmax(250px, 0.8fr);
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
}
|
||
|
||
.overview-copy {
|
||
padding: 22px;
|
||
border-right: 1px solid var(--line);
|
||
}
|
||
|
||
.overview-copy h3,
|
||
.evidence-summary h3 {
|
||
margin: 0 0 10px;
|
||
font-size: 17px;
|
||
}
|
||
|
||
.overview-copy p {
|
||
margin: 0;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.evidence-summary {
|
||
padding: 22px;
|
||
}
|
||
|
||
.runtime-list,
|
||
.compact-list,
|
||
.missing-list,
|
||
.action-list,
|
||
.freshness-list {
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.runtime-list li,
|
||
.compact-list li,
|
||
.missing-list li {
|
||
position: relative;
|
||
margin-top: 8px;
|
||
padding-left: 15px;
|
||
color: var(--muted);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.runtime-list li::before,
|
||
.compact-list li::before,
|
||
.missing-list li::before {
|
||
position: absolute;
|
||
top: 0.68em;
|
||
left: 0;
|
||
width: 5px;
|
||
height: 5px;
|
||
background: var(--implemented);
|
||
content: "";
|
||
}
|
||
|
||
.missing-list li::before {
|
||
background: var(--fault);
|
||
}
|
||
|
||
.maturity-scale {
|
||
display: grid;
|
||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||
margin-top: 16px;
|
||
border: 1px solid var(--line);
|
||
}
|
||
|
||
.maturity-step {
|
||
min-width: 0;
|
||
padding: 10px;
|
||
border-right: 1px solid var(--line);
|
||
color: var(--muted);
|
||
font-family: var(--mono);
|
||
font-size: 10px;
|
||
overflow-wrap: anywhere;
|
||
text-align: center;
|
||
}
|
||
|
||
.maturity-step:last-child {
|
||
border-right: 0;
|
||
}
|
||
|
||
.maturity-step[data-state="reached"] {
|
||
background: color-mix(in srgb, var(--verified) 10%, var(--surface));
|
||
color: var(--verified);
|
||
}
|
||
|
||
.maturity-step[data-state="missing"] {
|
||
color: var(--fault);
|
||
text-decoration: line-through;
|
||
text-decoration-thickness: 1px;
|
||
}
|
||
|
||
.capability-stack {
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
|
||
.capability-row {
|
||
display: grid;
|
||
grid-template-columns: 64px minmax(175px, 0.72fr) minmax(260px, 1.38fr);
|
||
gap: 16px;
|
||
align-items: start;
|
||
border-right: 1px solid var(--line);
|
||
border-bottom: 1px solid var(--line);
|
||
border-left: 1px solid var(--line);
|
||
background: var(--surface);
|
||
padding: 17px 18px;
|
||
}
|
||
|
||
.capability-row:hover {
|
||
background: var(--surface-raised);
|
||
}
|
||
|
||
.capability-index {
|
||
padding-top: 3px;
|
||
color: var(--faint);
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.capability-name {
|
||
margin: 0 0 8px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
line-height: 1.25;
|
||
}
|
||
|
||
.capability-claim {
|
||
margin: 0 0 10px;
|
||
color: var(--ink);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.capability-limit {
|
||
margin: 0;
|
||
color: var(--fault);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.status-tag {
|
||
display: inline-flex;
|
||
min-height: 26px;
|
||
align-items: center;
|
||
border: 1px solid currentColor;
|
||
border-radius: 1px;
|
||
padding: 3px 7px;
|
||
font-size: 9px;
|
||
font-weight: 600;
|
||
line-height: 1.15;
|
||
text-transform: uppercase;
|
||
white-space: normal;
|
||
}
|
||
|
||
.status-tag::before {
|
||
width: 6px;
|
||
height: 6px;
|
||
margin-right: 6px;
|
||
background: currentColor;
|
||
content: "";
|
||
}
|
||
|
||
.status-tag[data-tone="runtime"] {
|
||
color: var(--verified);
|
||
}
|
||
|
||
.status-tag[data-tone="tested"] {
|
||
color: #76b8aa;
|
||
}
|
||
|
||
:root[data-theme="light"] .status-tag[data-tone="tested"] {
|
||
color: #176f63;
|
||
}
|
||
|
||
.status-tag[data-tone="implemented"],
|
||
.status-tag[data-tone="declared"] {
|
||
color: var(--implemented);
|
||
}
|
||
|
||
.status-tag[data-tone="blocked"],
|
||
.status-tag[data-tone="not-passed"],
|
||
.status-tag[data-tone="prohibited"] {
|
||
color: var(--fault);
|
||
}
|
||
|
||
.status-tag[data-tone="unknown"] {
|
||
color: var(--amber);
|
||
}
|
||
|
||
.evidence-links {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px 12px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.evidence-links a {
|
||
font-family: var(--mono);
|
||
font-size: 10px;
|
||
}
|
||
|
||
.model-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
border-top: 1px solid var(--line);
|
||
border-left: 1px solid var(--line);
|
||
}
|
||
|
||
.model-entry {
|
||
min-width: 0;
|
||
border-right: 1px solid var(--line);
|
||
border-bottom: 1px solid var(--line);
|
||
background: var(--surface);
|
||
padding: 19px;
|
||
}
|
||
|
||
.model-entry__top {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.model-entry h3 {
|
||
margin: 0;
|
||
font-family: var(--mono);
|
||
font-size: 15px;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
.model-role {
|
||
min-height: 42px;
|
||
margin: 0 0 12px;
|
||
color: var(--implemented);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.model-claim,
|
||
.model-limit {
|
||
margin: 0 0 12px;
|
||
color: var(--muted);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.model-limit {
|
||
margin-bottom: 0;
|
||
color: var(--fault);
|
||
}
|
||
|
||
.filter-bar {
|
||
display: grid;
|
||
grid-template-columns: minmax(200px, 1.5fr) minmax(150px, 0.55fr) auto;
|
||
gap: 10px;
|
||
align-items: end;
|
||
margin-bottom: 12px;
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
padding: 12px;
|
||
}
|
||
|
||
.field-label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
color: var(--muted);
|
||
font-family: var(--mono);
|
||
font-size: 10px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
input[type="search"],
|
||
select {
|
||
width: 100%;
|
||
min-height: 44px;
|
||
border: 1px solid var(--line-strong);
|
||
border-radius: 1px;
|
||
background: var(--bg);
|
||
padding: 8px 11px;
|
||
}
|
||
|
||
.filter-count {
|
||
min-width: 90px;
|
||
padding: 11px 8px;
|
||
color: var(--muted);
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
text-align: right;
|
||
}
|
||
|
||
.matrix-wrap {
|
||
overflow-x: auto;
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
}
|
||
|
||
.platform-table,
|
||
.bundle-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
table-layout: fixed;
|
||
}
|
||
|
||
.platform-table {
|
||
min-width: 900px;
|
||
}
|
||
|
||
.platform-table th,
|
||
.platform-table td,
|
||
.bundle-table th,
|
||
.bundle-table td {
|
||
padding: 13px 12px;
|
||
border-right: 1px solid var(--line);
|
||
border-bottom: 1px solid var(--line);
|
||
vertical-align: top;
|
||
text-align: left;
|
||
}
|
||
|
||
.platform-table th:last-child,
|
||
.platform-table td:last-child,
|
||
.bundle-table th:last-child,
|
||
.bundle-table td:last-child {
|
||
border-right: 0;
|
||
}
|
||
|
||
.platform-table tr:last-child td,
|
||
.bundle-table tr:last-child td {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.platform-table th,
|
||
.bundle-table th {
|
||
background: var(--steel-soft);
|
||
color: var(--muted);
|
||
font-family: var(--mono);
|
||
font-size: 10px;
|
||
font-weight: 500;
|
||
letter-spacing: 0.04em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.platform-table tbody tr:hover,
|
||
.bundle-table tbody tr:hover {
|
||
background: var(--surface-raised);
|
||
}
|
||
|
||
.platform-name {
|
||
display: block;
|
||
margin-bottom: 8px;
|
||
font-weight: 600;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.cell-copy {
|
||
color: var(--muted);
|
||
font-size: 12px;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.cell-copy--fault {
|
||
color: var(--fault);
|
||
}
|
||
|
||
.gate-stack {
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
|
||
.gate-item {
|
||
border-right: 1px solid var(--line);
|
||
border-bottom: 1px solid var(--line);
|
||
border-left: 1px solid var(--line);
|
||
background: var(--surface);
|
||
}
|
||
|
||
.gate-item summary {
|
||
display: grid;
|
||
grid-template-columns: 52px minmax(150px, 0.55fr) minmax(220px, 1.45fr) auto;
|
||
gap: 14px;
|
||
align-items: center;
|
||
min-height: 62px;
|
||
padding: 10px 14px;
|
||
cursor: pointer;
|
||
list-style: none;
|
||
}
|
||
|
||
.gate-item summary::-webkit-details-marker {
|
||
display: none;
|
||
}
|
||
|
||
.gate-item summary::after {
|
||
display: block;
|
||
width: 18px;
|
||
height: 18px;
|
||
border-right: 2px solid var(--muted);
|
||
border-bottom: 2px solid var(--muted);
|
||
content: "";
|
||
transform: rotate(45deg) translate(-3px, 3px);
|
||
transition: transform 120ms ease;
|
||
}
|
||
|
||
.gate-item[open] summary::after {
|
||
transform: rotate(225deg) translate(-3px, 3px);
|
||
}
|
||
|
||
.gate-id {
|
||
color: var(--fault);
|
||
font-family: var(--mono);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.gate-name {
|
||
font-weight: 600;
|
||
}
|
||
|
||
.gate-acceptance {
|
||
color: var(--muted);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.gate-detail {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||
gap: 20px;
|
||
border-top: 1px solid var(--line);
|
||
background: var(--bg);
|
||
padding: 18px 20px 20px 80px;
|
||
}
|
||
|
||
.gate-detail h4 {
|
||
margin: 0 0 8px;
|
||
color: var(--muted);
|
||
font-family: var(--mono);
|
||
font-size: 10px;
|
||
font-weight: 500;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.zero-evidence {
|
||
margin: 0;
|
||
color: var(--fault);
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.bundle-table {
|
||
min-width: 760px;
|
||
}
|
||
|
||
.hash {
|
||
color: var(--muted);
|
||
font-size: 10px;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
.hash button {
|
||
min-width: 40px;
|
||
min-height: 40px;
|
||
margin-left: 4px;
|
||
border: 0;
|
||
background: transparent;
|
||
color: var(--link);
|
||
padding: 6px;
|
||
}
|
||
|
||
.provenance-board {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1.2fr) minmax(250px, 0.8fr);
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
}
|
||
|
||
.provenance-sources,
|
||
.provenance-hashes {
|
||
min-width: 0;
|
||
padding: 20px;
|
||
}
|
||
|
||
.provenance-sources {
|
||
border-right: 1px solid var(--line);
|
||
}
|
||
|
||
.provenance-board h3 {
|
||
margin: 0 0 12px;
|
||
font-size: 15px;
|
||
}
|
||
|
||
.source-list {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 8px 16px;
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.source-list a {
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
.hash-block {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.hash-block:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.hash-block span {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
color: var(--faint);
|
||
font-family: var(--mono);
|
||
font-size: 9px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.blocker-panel {
|
||
border-top: 3px solid var(--fault);
|
||
background: var(--surface);
|
||
box-shadow: 8px 8px 0 var(--shadow);
|
||
}
|
||
|
||
.panel-section {
|
||
border-right: 1px solid var(--line);
|
||
border-bottom: 1px solid var(--line);
|
||
border-left: 1px solid var(--line);
|
||
padding: 16px;
|
||
}
|
||
|
||
.panel-section h2,
|
||
.panel-section h3 {
|
||
margin: 0 0 12px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.panel-kicker {
|
||
margin: 0 0 5px;
|
||
color: var(--fault);
|
||
font-family: var(--mono);
|
||
font-size: 10px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.action-list {
|
||
counter-reset: action;
|
||
}
|
||
|
||
.action-list li {
|
||
position: relative;
|
||
margin-top: 14px;
|
||
padding: 0 0 14px 35px;
|
||
border-bottom: 1px solid var(--line);
|
||
counter-increment: action;
|
||
}
|
||
|
||
.action-list li:last-child {
|
||
padding-bottom: 0;
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.action-list li::before {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
color: var(--fault);
|
||
content: counter(action, decimal-leading-zero);
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.action-title {
|
||
display: block;
|
||
color: var(--ink);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.action-gates {
|
||
display: block;
|
||
margin-top: 4px;
|
||
color: var(--faint);
|
||
font-family: var(--mono);
|
||
font-size: 9px;
|
||
}
|
||
|
||
.freshness-list li {
|
||
margin-top: 12px;
|
||
padding-bottom: 12px;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
|
||
.freshness-list li:last-child {
|
||
padding-bottom: 0;
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.freshness-name,
|
||
.freshness-value,
|
||
.freshness-note {
|
||
display: block;
|
||
}
|
||
|
||
.freshness-name {
|
||
color: var(--muted);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.freshness-value {
|
||
margin-top: 2px;
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.freshness-note {
|
||
margin-top: 3px;
|
||
color: var(--faint);
|
||
font-size: 10px;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.legend-list {
|
||
display: grid;
|
||
gap: 8px;
|
||
margin: 0;
|
||
}
|
||
|
||
.legend-item {
|
||
display: grid;
|
||
grid-template-columns: minmax(106px, auto) 1fr;
|
||
gap: 8px;
|
||
align-items: start;
|
||
}
|
||
|
||
.legend-item dd,
|
||
.legend-item dt {
|
||
margin: 0;
|
||
}
|
||
|
||
.legend-item dd {
|
||
color: var(--faint);
|
||
font-size: 10px;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.page-footer {
|
||
display: grid;
|
||
grid-template-columns: 1fr auto;
|
||
gap: 24px;
|
||
align-items: end;
|
||
margin-top: 52px;
|
||
border-top: 1px solid var(--line-strong);
|
||
padding-top: 18px;
|
||
color: var(--faint);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.page-footer p {
|
||
max-width: 880px;
|
||
margin: 0;
|
||
}
|
||
|
||
.page-footer a {
|
||
font-family: var(--mono);
|
||
}
|
||
|
||
.visually-hidden {
|
||
position: absolute !important;
|
||
width: 1px !important;
|
||
height: 1px !important;
|
||
padding: 0 !important;
|
||
margin: -1px !important;
|
||
overflow: hidden !important;
|
||
clip: rect(0, 0, 0, 0) !important;
|
||
white-space: nowrap !important;
|
||
border: 0 !important;
|
||
}
|
||
|
||
[hidden] {
|
||
display: none !important;
|
||
}
|
||
|
||
@media (max-width: 1260px) {
|
||
.audit-grid {
|
||
grid-template-columns: 156px minmax(0, 1fr);
|
||
}
|
||
|
||
.blocker-panel {
|
||
position: static;
|
||
grid-column: 1 / -1;
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
box-shadow: none;
|
||
}
|
||
|
||
.panel-section {
|
||
border-top: 0;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 960px) {
|
||
.page-shell {
|
||
padding-right: 18px;
|
||
padding-left: 18px;
|
||
}
|
||
|
||
.masthead {
|
||
grid-template-columns: 1fr 1.5fr;
|
||
}
|
||
|
||
.masthead__claim {
|
||
border-right: 0;
|
||
}
|
||
|
||
.masthead__tools {
|
||
grid-column: 1 / -1;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
|
||
.metrics {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
|
||
.metric:nth-child(2) {
|
||
border-right: 0;
|
||
}
|
||
|
||
.metric:nth-child(-n + 2) {
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
|
||
.audit-grid {
|
||
display: block;
|
||
}
|
||
|
||
.rail {
|
||
position: static;
|
||
display: flex;
|
||
overflow-x: auto;
|
||
margin-bottom: 26px;
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
}
|
||
|
||
.rail__label {
|
||
display: none;
|
||
}
|
||
|
||
.rail a {
|
||
grid-template-columns: auto auto;
|
||
flex: 0 0 auto;
|
||
border-bottom: 3px solid transparent;
|
||
border-left: 0;
|
||
}
|
||
|
||
.rail a:hover,
|
||
.rail a[aria-current="true"] {
|
||
border-bottom-color: var(--verified);
|
||
border-left: 0;
|
||
}
|
||
|
||
.blocker-panel {
|
||
margin-top: 24px;
|
||
}
|
||
|
||
.model-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.model-role {
|
||
min-height: 0;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 720px) {
|
||
.masthead {
|
||
display: block;
|
||
box-shadow: 5px 5px 0 var(--shadow);
|
||
}
|
||
|
||
.masthead__brand,
|
||
.masthead__claim {
|
||
border-right: 0;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
|
||
.masthead__tools {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
border-top: 0;
|
||
}
|
||
|
||
.safety-banner {
|
||
grid-template-columns: auto 1fr;
|
||
}
|
||
|
||
.snapshot-label {
|
||
grid-column: 2;
|
||
white-space: normal;
|
||
}
|
||
|
||
.overview-board,
|
||
.provenance-board {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.overview-copy,
|
||
.provenance-sources {
|
||
border-right: 0;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
|
||
.maturity-scale {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.maturity-step {
|
||
border-right: 0;
|
||
border-bottom: 1px solid var(--line);
|
||
text-align: left;
|
||
}
|
||
|
||
.maturity-step:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.capability-row {
|
||
grid-template-columns: 42px minmax(0, 1fr);
|
||
}
|
||
|
||
.capability-evidence {
|
||
grid-column: 1 / -1;
|
||
padding-left: 58px;
|
||
}
|
||
|
||
.filter-bar {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.filter-count {
|
||
padding: 0;
|
||
text-align: left;
|
||
}
|
||
|
||
.gate-item summary {
|
||
grid-template-columns: 44px minmax(0, 1fr) auto;
|
||
}
|
||
|
||
.gate-acceptance {
|
||
grid-column: 2;
|
||
}
|
||
|
||
.gate-detail {
|
||
grid-template-columns: 1fr;
|
||
padding-left: 72px;
|
||
}
|
||
|
||
.source-list {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.blocker-panel {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.page-footer {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 460px) {
|
||
.page-shell {
|
||
padding: 10px 10px 48px;
|
||
}
|
||
|
||
.metrics {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.metric,
|
||
.metric:nth-child(2) {
|
||
border-right: 0;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
|
||
.metric:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.section-header {
|
||
grid-template-columns: 48px minmax(0, 1fr);
|
||
gap: 8px;
|
||
}
|
||
|
||
.capability-row {
|
||
display: block;
|
||
}
|
||
|
||
.capability-index {
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.capability-evidence {
|
||
padding-left: 0;
|
||
}
|
||
|
||
.gate-item summary {
|
||
grid-template-columns: 40px minmax(0, 1fr) auto;
|
||
}
|
||
|
||
.gate-acceptance {
|
||
display: none;
|
||
}
|
||
|
||
.gate-detail {
|
||
padding: 16px;
|
||
}
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
html {
|
||
scroll-behavior: auto;
|
||
}
|
||
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
transition-duration: 0.01ms !important;
|
||
animation-duration: 0.01ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
}
|
||
}
|
||
|
||
@media print {
|
||
:root,
|
||
:root[data-theme="light"] {
|
||
color-scheme: light;
|
||
--bg: #ffffff;
|
||
--surface: #ffffff;
|
||
--surface-raised: #ffffff;
|
||
--steel: #e8e8e8;
|
||
--steel-soft: #f2f2f2;
|
||
--line: #b5b5b5;
|
||
--line-strong: #777777;
|
||
--ink: #111111;
|
||
--muted: #444444;
|
||
--faint: #555555;
|
||
--verified: #1b6b43;
|
||
--implemented: #315c70;
|
||
--fault: #982a26;
|
||
--link: #1b5a75;
|
||
--shadow: transparent;
|
||
}
|
||
|
||
body {
|
||
background: #ffffff;
|
||
}
|
||
|
||
.page-shell {
|
||
width: 100%;
|
||
padding: 0;
|
||
}
|
||
|
||
.masthead,
|
||
.blocker-panel {
|
||
box-shadow: none;
|
||
}
|
||
|
||
.masthead__tools,
|
||
.rail,
|
||
.filter-bar {
|
||
display: none;
|
||
}
|
||
|
||
.audit-grid {
|
||
display: block;
|
||
}
|
||
|
||
.audit-section {
|
||
break-inside: avoid;
|
||
}
|
||
|
||
.blocker-panel {
|
||
position: static;
|
||
margin-top: 24px;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<a class="skip-link" href="#main-content">跳到主要内容</a>
|
||
|
||
<svg class="visually-hidden" aria-hidden="true">
|
||
<!-- Inline Lucide-compatible symbols keep the page functional without a JS icon CDN. -->
|
||
<symbol id="icon-shield-alert" viewBox="0 0 24 24">
|
||
<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67 0C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"></path>
|
||
<path d="M12 8v4"></path>
|
||
<path d="M12 16h.01"></path>
|
||
</symbol>
|
||
<symbol id="icon-sun-moon" viewBox="0 0 24 24">
|
||
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9"></path>
|
||
<path d="M19 3v4"></path>
|
||
<path d="M21 5h-4"></path>
|
||
</symbol>
|
||
<symbol id="icon-copy" viewBox="0 0 24 24">
|
||
<rect width="14" height="14" x="8" y="8" rx="2"></rect>
|
||
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path>
|
||
</symbol>
|
||
<symbol id="icon-external" viewBox="0 0 24 24">
|
||
<path d="M15 3h6v6"></path>
|
||
<path d="M10 14 21 3"></path>
|
||
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
||
</symbol>
|
||
</svg>
|
||
|
||
<div class="page-shell">
|
||
<header class="masthead" aria-labelledby="page-title">
|
||
<div class="masthead__brand">
|
||
<p class="eyebrow">Release control / public snapshot</p>
|
||
<h1 class="brand-title" id="page-title">Quant OS</h1>
|
||
<p class="brand-subtitle">个人 A 股研究到执行的证据审计台</p>
|
||
</div>
|
||
<div class="masthead__claim">
|
||
<div class="claim-line">
|
||
<p class="claim-title" id="claim-status">STATUS DATA UNAVAILABLE</p>
|
||
<span class="status-tag" data-tone="blocked" id="claim-gates">0 / 10 GATES</span>
|
||
</div>
|
||
<p class="claim-copy" id="claim-reason">
|
||
当前页面尚未加载构建时状态快照。缺少数据时默认判定为不可发布、不可实盘。
|
||
</p>
|
||
</div>
|
||
<div class="masthead__tools">
|
||
<button class="tool-button" id="theme-toggle" type="button" aria-label="切换明暗主题">
|
||
<svg class="icon" aria-hidden="true"><use href="#icon-sun-moon"></use></svg>
|
||
<span id="theme-label">切换浅色</span>
|
||
</button>
|
||
<span class="sync-note" id="snapshot-meta">BUILD SNAPSHOT · WAITING FOR DATA</span>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="safety-banner" role="note" aria-label="资金安全边界">
|
||
<svg class="icon" aria-hidden="true"><use href="#icon-shield-alert"></use></svg>
|
||
<p><strong>可运行框架 ≠ 可投入资金。</strong> 本页只呈现构建时证据快照,不是实时服务健康监控,也不构成投资收益声明。</p>
|
||
<span class="snapshot-label">LIVE READY = FALSE</span>
|
||
</div>
|
||
|
||
<section class="metrics" aria-label="核心状态指标">
|
||
<div class="metric">
|
||
<span class="metric__label">Delivery score</span>
|
||
<strong class="metric__value" id="metric-score">NOT SCORED</strong>
|
||
<span class="metric__note">不把文章估分冒充系统得分</span>
|
||
</div>
|
||
<div class="metric">
|
||
<span class="metric__label">Gate evidence</span>
|
||
<strong class="metric__value" id="metric-gates">0 / 10</strong>
|
||
<span class="metric__note">必须全部有发布级证据</span>
|
||
</div>
|
||
<div class="metric">
|
||
<span class="metric__label">Recorded tests</span>
|
||
<strong class="metric__value" id="metric-tests">—</strong>
|
||
<span class="metric__note" id="metric-tests-note">历史记录,不是线上健康检查</span>
|
||
</div>
|
||
<div class="metric">
|
||
<span class="metric__label">Audit snapshot</span>
|
||
<strong class="metric__value" id="metric-audit">—</strong>
|
||
<span class="metric__note">静态、可追溯、非实时</span>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="audit-grid">
|
||
<nav class="rail" aria-label="验收页章节">
|
||
<span class="rail__label">System map</span>
|
||
<a href="#overview"><span class="rail__index">00</span><span>总览</span></a>
|
||
<a href="#layers"><span class="rail__index">01</span><span>系统分层</span></a>
|
||
<a href="#models"><span class="rail__index">02</span><span>模型边界</span></a>
|
||
<a href="#platforms"><span class="rail__index">03</span><span>平台接入</span></a>
|
||
<a href="#gates"><span class="rail__index">04</span><span>G1–G10</span></a>
|
||
<a href="#bundles"><span class="rail__index">05</span><span>发布包</span></a>
|
||
<a href="#provenance"><span class="rail__index">06</span><span>证据来源</span></a>
|
||
</nav>
|
||
|
||
<main class="main-content" id="main-content" tabindex="-1">
|
||
<div class="loading-state" id="loading-state" role="status" aria-live="polite">
|
||
正在读取脱敏的构建状态快照……
|
||
</div>
|
||
<div class="error-state" id="error-state" role="alert" hidden>
|
||
<strong>STATUS DATA UNAVAILABLE</strong><br>
|
||
状态数据未加载。为避免误判,本页不会在缺失证据时显示“已发布”或“可实盘”。
|
||
</div>
|
||
|
||
<section class="audit-section" id="overview" aria-labelledby="overview-title">
|
||
<div class="section-header">
|
||
<span class="section-code">SEC.00</span>
|
||
<div>
|
||
<h2 class="section-title" id="overview-title">证据优先的系统总览</h2>
|
||
<p class="section-intro">页面区分代码存在、合同测试、真实运行片段和发布验收。绿色不代表收益,真实运行也不自动获得 Gate。</p>
|
||
</div>
|
||
</div>
|
||
<div class="overview-board">
|
||
<div class="overview-copy">
|
||
<h3>当前判定</h3>
|
||
<p id="overview-reason">等待状态快照。缺失状态时按 NOT_BASELINE_60 处理。</p>
|
||
<div class="maturity-scale" aria-label="证据成熟度阶梯">
|
||
<span class="maturity-step" data-state="reached">DECLARED</span>
|
||
<span class="maturity-step" data-state="reached">IMPLEMENTED</span>
|
||
<span class="maturity-step" data-state="reached">CONTRACT VERIFIED</span>
|
||
<span class="maturity-step" data-state="reached">RUNTIME SMOKE</span>
|
||
<span class="maturity-step" data-state="missing">RELEASE VERIFIED</span>
|
||
</div>
|
||
</div>
|
||
<div class="evidence-summary">
|
||
<h3>已发生的真实运行片段</h3>
|
||
<ul class="runtime-list" id="runtime-list">
|
||
<li>等待状态数据</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="audit-section" id="layers" aria-labelledby="layers-title">
|
||
<div class="section-header">
|
||
<span class="section-code">SEC.01</span>
|
||
<div>
|
||
<h2 class="section-title" id="layers-title">系统分层与完成边界</h2>
|
||
<p class="section-intro">从数据时点到券商运营逐层查看:每一层同时展示已实现能力、证据级别和仍然阻断上线的事项。</p>
|
||
</div>
|
||
</div>
|
||
<div class="capability-stack" id="layer-list"></div>
|
||
</section>
|
||
|
||
<section class="audit-section" id="models" aria-labelledby="models-title">
|
||
<div class="section-header">
|
||
<span class="section-code">SEC.02</span>
|
||
<div>
|
||
<h2 class="section-title" id="models-title">模型与策略边界</h2>
|
||
<p class="section-intro">当前没有冻结的 production champion。共享计算基线和研究候选必须分开审查,fixture 表现不等于投资价值。</p>
|
||
</div>
|
||
</div>
|
||
<div class="model-grid" id="model-list"></div>
|
||
</section>
|
||
|
||
<section class="audit-section" id="platforms" aria-labelledby="platforms-title">
|
||
<div class="section-header">
|
||
<span class="section-code">SEC.03</span>
|
||
<div>
|
||
<h2 class="section-title" id="platforms-title">平台与服务接入矩阵</h2>
|
||
<p class="section-intro">“有入口”和“已在目标平台验证”是两件事。筛选 Local、Colab、聚宽、Qlib、QMT 和 XtTrader 的真实状态。</p>
|
||
</div>
|
||
</div>
|
||
<div class="filter-bar" role="search">
|
||
<div>
|
||
<label class="field-label" for="platform-search">搜索平台、用途或缺口</label>
|
||
<input id="platform-search" type="search" placeholder="例如:QMT、PIT、shadow" autocomplete="off">
|
||
</div>
|
||
<div>
|
||
<label class="field-label" for="platform-status">证据级别</label>
|
||
<select id="platform-status">
|
||
<option value="all">全部级别</option>
|
||
<option value="real_runtime">真实运行片段</option>
|
||
<option value="tested">合同验证</option>
|
||
<option value="implemented">已实现</option>
|
||
<option value="blocked">外部阻断</option>
|
||
</select>
|
||
</div>
|
||
<div class="filter-count" id="platform-count" aria-live="polite">0 / 0</div>
|
||
</div>
|
||
<div class="matrix-wrap">
|
||
<table class="platform-table">
|
||
<caption class="visually-hidden">Quant OS 平台能力、运行前置条件、现有证据与发布缺口</caption>
|
||
<colgroup>
|
||
<col style="width: 19%">
|
||
<col style="width: 20%">
|
||
<col style="width: 28%">
|
||
<col style="width: 33%">
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th scope="col">Path / status</th>
|
||
<th scope="col">Intended use / prerequisite</th>
|
||
<th scope="col">Verified fact</th>
|
||
<th scope="col">Missing release evidence</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="platform-body"></tbody>
|
||
</table>
|
||
<p class="empty-state" id="platform-empty" hidden>没有符合当前筛选条件的平台能力。</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="audit-section" id="gates" aria-labelledby="gates-title">
|
||
<div class="section-header">
|
||
<span class="section-code">SEC.04</span>
|
||
<div>
|
||
<h2 class="section-title" id="gates-title">Baseline 60 · G1–G10</h2>
|
||
<p class="section-intro">Gate 是发布闸门,不是代码清单。展开每项查看验收定义和缺失证据;当前 10 项均未通过。</p>
|
||
</div>
|
||
</div>
|
||
<div class="gate-stack" id="gate-list"></div>
|
||
</section>
|
||
|
||
<section class="audit-section" id="bundles" aria-labelledby="bundles-title">
|
||
<div class="section-header">
|
||
<span class="section-code">SEC.05</span>
|
||
<div>
|
||
<h2 class="section-title" id="bundles-title">跨平台发布包完整性</h2>
|
||
<p class="section-intro">构建器核对共享核心、wrapper、配置与生成单文件的 SHA-256。哈希一致只证明代码发布包完整,不证明目标平台通过。</p>
|
||
</div>
|
||
</div>
|
||
<div class="matrix-wrap">
|
||
<table class="bundle-table">
|
||
<caption class="visually-hidden">JoinQuant 与 QMT 单文件发布包及其构建哈希</caption>
|
||
<thead>
|
||
<tr>
|
||
<th scope="col">Bundle</th>
|
||
<th scope="col">Output</th>
|
||
<th scope="col">Output SHA-256</th>
|
||
<th scope="col">Config SHA-256</th>
|
||
<th scope="col">Integrity</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="bundle-body"></tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="audit-section" id="provenance" aria-labelledby="provenance-title">
|
||
<div class="section-header">
|
||
<span class="section-code">SEC.06</span>
|
||
<div>
|
||
<h2 class="section-title" id="provenance-title">证据来源与快照血缘</h2>
|
||
<p class="section-intro">所有公开字段由仓库中的权威记录生成并脱敏。链接指向私有 Gitea 源码,访问时可能要求登录。</p>
|
||
</div>
|
||
</div>
|
||
<div class="provenance-board">
|
||
<div class="provenance-sources">
|
||
<h3>可审查来源</h3>
|
||
<ul class="source-list" id="source-list"></ul>
|
||
</div>
|
||
<div class="provenance-hashes">
|
||
<h3>快照指纹</h3>
|
||
<div class="hash-block">
|
||
<span>Public payload</span>
|
||
<code class="hash" id="payload-hash">—</code>
|
||
</div>
|
||
<div class="hash-block">
|
||
<span>Source set</span>
|
||
<code class="hash" id="source-hash">—</code>
|
||
</div>
|
||
<div class="hash-block">
|
||
<span>Portable core</span>
|
||
<code class="hash" id="core-hash">—</code>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<aside class="blocker-panel" aria-labelledby="blockers-title">
|
||
<section class="panel-section">
|
||
<p class="panel-kicker">Release blockers</p>
|
||
<h2 id="blockers-title">下一步必须补的证据</h2>
|
||
<ol class="action-list" id="action-list"></ol>
|
||
</section>
|
||
<section class="panel-section">
|
||
<p class="panel-kicker">Freshness</p>
|
||
<h3>数据与证据截止日</h3>
|
||
<ul class="freshness-list" id="freshness-list">
|
||
<li>
|
||
<span class="freshness-name">状态快照</span>
|
||
<strong class="freshness-value">等待数据</strong>
|
||
<span class="freshness-note">不把交易日历日期当作行情新鲜度</span>
|
||
</li>
|
||
</ul>
|
||
</section>
|
||
<section class="panel-section">
|
||
<p class="panel-kicker">Legend</p>
|
||
<h3>状态口径</h3>
|
||
<dl class="legend-list">
|
||
<div class="legend-item">
|
||
<dt><span class="status-tag" data-tone="implemented">已实现</span></dt>
|
||
<dd>仓库存在实现;未证明目标 runtime。</dd>
|
||
</div>
|
||
<div class="legend-item">
|
||
<dt><span class="status-tag" data-tone="tested">合同验证</span></dt>
|
||
<dd>单测、fake 或 fixture 通过。</dd>
|
||
</div>
|
||
<div class="legend-item">
|
||
<dt><span class="status-tag" data-tone="runtime">真实运行片段</span></dt>
|
||
<dd>目标 runtime 局部运行;不等于发布验收。</dd>
|
||
</div>
|
||
<div class="legend-item">
|
||
<dt><span class="status-tag" data-tone="blocked">外部阻断</span></dt>
|
||
<dd>仍需账号、客户端、数据或合规证据。</dd>
|
||
</div>
|
||
</dl>
|
||
</section>
|
||
</aside>
|
||
</div>
|
||
|
||
<footer class="page-footer">
|
||
<p>本页是公开、脱敏的构建时快照。未发布本地行情、运行 artifacts、券商状态或可复用凭据。任何实盘决策必须回到 G1–G10 的发布级证据。</p>
|
||
<a href="https://git.gomars.fun/boat/quants-strategies/src/branch/master/quant-os" target="_blank" rel="noopener noreferrer">
|
||
源码(需登录)
|
||
<svg class="icon" aria-hidden="true"><use href="#icon-external"></use></svg>
|
||
</a>
|
||
</footer>
|
||
</div>
|
||
|
||
<noscript>
|
||
<div class="page-shell">
|
||
<div class="error-state" role="alert">
|
||
<strong>STATUS DATA UNAVAILABLE</strong><br>
|
||
JavaScript 已禁用,因此无法读取脱敏状态快照。保守结论:NOT_BASELINE_60、0/10 Gate、不可实盘。
|
||
</div>
|
||
</div>
|
||
</noscript>
|
||
|
||
<script src="./status-data.js"></script>
|
||
<script>
|
||
(() => {
|
||
"use strict";
|
||
|
||
const repoBase = "https://git.gomars.fun/boat/quants-strategies/src/branch/master/quant-os/";
|
||
const statusLabels = {
|
||
implemented: { label: "已实现", tone: "implemented" },
|
||
tested: { label: "合同验证", tone: "tested" },
|
||
real_runtime: { label: "真实运行片段", tone: "runtime" },
|
||
blocked: { label: "外部阻断", tone: "blocked" },
|
||
not_passed: { label: "未通过", tone: "not-passed" },
|
||
prohibited: { label: "禁止", tone: "prohibited" },
|
||
declared: { label: "已声明", tone: "declared" }
|
||
};
|
||
|
||
const state = {
|
||
data: null,
|
||
evidenceById: new Map(),
|
||
platformQuery: "",
|
||
platformStatus: "all"
|
||
};
|
||
|
||
const byId = (id) => document.getElementById(id);
|
||
|
||
const escapeHtml = (value) => String(value ?? "")
|
||
.replaceAll("&", "&")
|
||
.replaceAll("<", "<")
|
||
.replaceAll(">", ">")
|
||
.replaceAll('"', """)
|
||
.replaceAll("'", "'");
|
||
|
||
const safeRepoPath = (path) => {
|
||
const value = String(path ?? "");
|
||
if (!value || value.startsWith("/") || value.includes("..") || value.includes("\\")) {
|
||
return null;
|
||
}
|
||
return value;
|
||
};
|
||
|
||
const evidenceUrl = (id) => {
|
||
const evidence = state.evidenceById.get(id);
|
||
const path = evidence && safeRepoPath(evidence.path);
|
||
return path ? repoBase + path.split("/").map(encodeURIComponent).join("/") : null;
|
||
};
|
||
|
||
const evidenceLinks = (ids = []) => {
|
||
const links = ids.map((id) => {
|
||
const item = state.evidenceById.get(id);
|
||
const url = evidenceUrl(id);
|
||
if (!item || !url) return "";
|
||
return `<a href="${escapeHtml(url)}" target="_blank" rel="noopener noreferrer">${escapeHtml(item.label)} ↗</a>`;
|
||
}).filter(Boolean);
|
||
return links.length ? `<div class="evidence-links">${links.join("")}</div>` : "";
|
||
};
|
||
|
||
const statusTag = (status) => {
|
||
const normalized = String(status ?? "").toLowerCase();
|
||
const config = statusLabels[normalized] || { label: normalized || "未知", tone: "unknown" };
|
||
return `<span class="status-tag" data-tone="${escapeHtml(config.tone)}">${escapeHtml(config.label)}</span>`;
|
||
};
|
||
|
||
const listItems = (items, className = "compact-list") => {
|
||
const values = Array.isArray(items) ? items : [];
|
||
if (!values.length) return `<p class="zero-evidence">NONE RECORDED</p>`;
|
||
return `<ul class="${className}">${values.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>`;
|
||
};
|
||
|
||
const shortHash = (value, left = 10, right = 8) => {
|
||
const text = String(value ?? "");
|
||
return text.length > left + right + 3 ? `${text.slice(0, left)}…${text.slice(-right)}` : text;
|
||
};
|
||
|
||
const renderHeader = (data) => {
|
||
const claim = data.claim || {};
|
||
const summary = data.summary || {};
|
||
byId("claim-status").textContent = claim.status || "NOT_BASELINE_60";
|
||
byId("claim-gates").textContent = `${claim.gatesPassed ?? 0} / ${claim.gatesTotal ?? 10} GATES`;
|
||
byId("claim-reason").textContent = claim.reason || "缺少发布级证据。";
|
||
byId("overview-reason").textContent = claim.reason || "缺少发布级证据。";
|
||
byId("metric-score").textContent = claim.score == null
|
||
? String(claim.scoreStatus || "not_scored").replaceAll("_", " ").toUpperCase()
|
||
: String(claim.score);
|
||
byId("metric-gates").textContent = `${claim.gatesPassed ?? 0} / ${claim.gatesTotal ?? 10}`;
|
||
byId("metric-tests").textContent = summary.testsRecorded == null ? "—" : String(summary.testsRecorded);
|
||
byId("metric-tests-note").textContent = summary.optionalSkipsRecorded == null
|
||
? "Scorecard 历史记录,不是线上健康检查"
|
||
: `最近记录 ${summary.optionalSkipsRecorded} optional skips;非线上健康检查`;
|
||
byId("metric-audit").textContent = data.auditAsOf || "—";
|
||
byId("snapshot-meta").textContent = data.generatedAtSource === "audit_as_of"
|
||
? `EVIDENCE AS-OF · ${data.auditAsOf || "UNKNOWN"} · REPRODUCIBLE SNAPSHOT`
|
||
: `GENERATED · ${data.generatedAt || "UNKNOWN"} · SCHEMA ${data.schemaVersion || "?"}`;
|
||
|
||
const runtimes = Array.isArray(summary.realRuntimeSmokes) ? summary.realRuntimeSmokes : [];
|
||
byId("runtime-list").innerHTML = runtimes.length
|
||
? runtimes.map((item) => `<li>${escapeHtml(item)}</li>`).join("")
|
||
: "<li>无真实运行证据记录</li>";
|
||
};
|
||
|
||
const renderLayers = (data) => {
|
||
const layers = Array.isArray(data.layers) ? data.layers : [];
|
||
byId("layer-list").innerHTML = layers.map((layer, index) => `
|
||
<article class="capability-row">
|
||
<div class="capability-index">L${String(index + 1).padStart(2, "0")}</div>
|
||
<div>
|
||
<h3 class="capability-name">${escapeHtml(layer.name)}</h3>
|
||
${statusTag(layer.status)}
|
||
${listItems(layer.capabilities)}
|
||
</div>
|
||
<div class="capability-evidence">
|
||
<p class="capability-claim">${escapeHtml(layer.claim)}</p>
|
||
${(layer.limitations || []).map((item) => `<p class="capability-limit">缺口 · ${escapeHtml(item)}</p>`).join("")}
|
||
${evidenceLinks(layer.evidenceLinks)}
|
||
</div>
|
||
</article>
|
||
`).join("");
|
||
};
|
||
|
||
const renderModels = (data) => {
|
||
const models = Array.isArray(data.models) ? data.models : [];
|
||
byId("model-list").innerHTML = models.map((model) => `
|
||
<article class="model-entry">
|
||
<div class="model-entry__top">
|
||
<h3>${escapeHtml(model.name)}</h3>
|
||
${statusTag(model.status)}
|
||
</div>
|
||
<p class="model-role">${escapeHtml(model.role)}</p>
|
||
<p class="model-claim">${escapeHtml(model.claim)}</p>
|
||
${(model.limitations || []).map((item) => `<p class="model-limit">限制 · ${escapeHtml(item)}</p>`).join("")}
|
||
${evidenceLinks(model.evidenceLinks)}
|
||
</article>
|
||
`).join("");
|
||
};
|
||
|
||
const renderPlatforms = () => {
|
||
const platforms = Array.isArray(state.data?.platforms) ? state.data.platforms : [];
|
||
const query = state.platformQuery.trim().toLocaleLowerCase("zh-CN");
|
||
const filtered = platforms.filter((platform) => {
|
||
const statusMatches = state.platformStatus === "all" || platform.status === state.platformStatus;
|
||
const haystack = [
|
||
platform.name,
|
||
platform.intendedUse,
|
||
platform.prerequisite,
|
||
platform.claim,
|
||
...(platform.limitations || [])
|
||
].join(" ").toLocaleLowerCase("zh-CN");
|
||
return statusMatches && (!query || haystack.includes(query));
|
||
});
|
||
|
||
byId("platform-body").innerHTML = filtered.map((platform) => `
|
||
<tr>
|
||
<td>
|
||
<strong class="platform-name">${escapeHtml(platform.name)}</strong>
|
||
${statusTag(platform.status)}
|
||
${evidenceLinks(platform.evidenceLinks)}
|
||
</td>
|
||
<td>
|
||
<div class="cell-copy">${escapeHtml(platform.intendedUse)}</div>
|
||
<div class="cell-copy"><span class="table-label">RUNTIME:</span> ${escapeHtml(platform.prerequisite)}</div>
|
||
</td>
|
||
<td><div class="cell-copy">${escapeHtml(platform.claim)}</div></td>
|
||
<td>${listItems(platform.limitations, "missing-list")}</td>
|
||
</tr>
|
||
`).join("");
|
||
|
||
byId("platform-count").textContent = `${filtered.length} / ${platforms.length}`;
|
||
byId("platform-empty").hidden = filtered.length !== 0;
|
||
};
|
||
|
||
const renderGates = (data) => {
|
||
const gates = Array.isArray(data.gates) ? data.gates : [];
|
||
byId("gate-list").innerHTML = gates.map((gate) => `
|
||
<details class="gate-item">
|
||
<summary>
|
||
<span class="gate-id">${escapeHtml(gate.id)}</span>
|
||
<span class="gate-name">${escapeHtml(gate.name)}</span>
|
||
<span class="gate-acceptance">${escapeHtml(gate.acceptance)}</span>
|
||
${statusTag(gate.status)}
|
||
</summary>
|
||
<div class="gate-detail">
|
||
<div>
|
||
<h4>Required evidence</h4>
|
||
${listItems(gate.requiredEvidence, "missing-list")}
|
||
</div>
|
||
<div>
|
||
<h4>Actual release evidence</h4>
|
||
${Array.isArray(gate.evidence) && gate.evidence.length
|
||
? listItems(gate.evidence)
|
||
: '<p class="zero-evidence">EVIDENCE = [ ] · 未通过,不计分</p>'}
|
||
${evidenceLinks(gate.evidenceLinks)}
|
||
</div>
|
||
</div>
|
||
</details>
|
||
`).join("");
|
||
};
|
||
|
||
const renderBundles = (data) => {
|
||
const bundles = Array.isArray(data.bundles?.artifacts) ? data.bundles.artifacts : [];
|
||
byId("bundle-body").innerHTML = bundles.map((bundle) => `
|
||
<tr>
|
||
<td><strong>${escapeHtml(bundle.id)}</strong></td>
|
||
<td><code class="hash">${escapeHtml(bundle.output)}</code></td>
|
||
<td><code class="hash" title="${escapeHtml(bundle.outputSha256)}">${escapeHtml(shortHash(bundle.outputSha256))}</code></td>
|
||
<td><code class="hash" title="${escapeHtml(bundle.effectiveConfigSha256)}">${escapeHtml(shortHash(bundle.effectiveConfigSha256))}</code></td>
|
||
<td>${statusTag(bundle.integrity === "manifest_hashes_match_repository" ? "tested" : "blocked")}</td>
|
||
</tr>
|
||
`).join("");
|
||
};
|
||
|
||
const renderActions = (data) => {
|
||
const actions = Array.isArray(data.nextActions) ? data.nextActions : [];
|
||
byId("action-list").innerHTML = actions.map((action) => `
|
||
<li>
|
||
<span class="action-title">${escapeHtml(action.title)}</span>
|
||
<span class="action-gates">${escapeHtml((action.gateIds || []).join(" · "))}</span>
|
||
</li>
|
||
`).join("");
|
||
};
|
||
|
||
const fallbackFreshness = (data) => [
|
||
{
|
||
name: "项目审计",
|
||
value: data.auditAsOf || "N/A",
|
||
note: "页面是构建时证据快照,不是实时探针。"
|
||
},
|
||
{
|
||
name: "授权 JQData",
|
||
value: "N/A · BLOCKED",
|
||
note: "尚无真实不可变快照;不得显示为最新。"
|
||
},
|
||
{
|
||
name: "QMT / broker",
|
||
value: "N/A · BLOCKED",
|
||
note: "尚无真实运行与券商认证。"
|
||
}
|
||
];
|
||
|
||
const renderFreshness = (data) => {
|
||
const items = Array.isArray(data.freshness) && data.freshness.length
|
||
? data.freshness
|
||
: fallbackFreshness(data);
|
||
byId("freshness-list").innerHTML = items.map((item) => `
|
||
<li>
|
||
<span class="freshness-name">${escapeHtml(item.name || item.label)}</span>
|
||
<strong class="freshness-value">${escapeHtml(item.value || item.asOf || "N/A")}${item.status === "blocked" ? " · BLOCKED" : ""}</strong>
|
||
<span class="freshness-note">${escapeHtml(item.semantics || item.note || item.qualifier || "")}</span>
|
||
</li>
|
||
`).join("");
|
||
};
|
||
|
||
const renderProvenance = (data) => {
|
||
const evidence = Array.isArray(data.evidence) ? data.evidence : [];
|
||
byId("source-list").innerHTML = evidence.map((item) => {
|
||
const url = evidenceUrl(item.id);
|
||
return url
|
||
? `<li><a href="${escapeHtml(url)}" target="_blank" rel="noopener noreferrer">${escapeHtml(item.path)} ↗</a></li>`
|
||
: "";
|
||
}).join("");
|
||
byId("payload-hash").textContent = data.provenance?.payloadSha256 || "—";
|
||
byId("source-hash").textContent = data.provenance?.sourceSetSha256 || "—";
|
||
byId("core-hash").textContent = data.bundles?.portableCoreSha256 || "—";
|
||
};
|
||
|
||
const setupFilters = () => {
|
||
byId("platform-search").addEventListener("input", (event) => {
|
||
state.platformQuery = event.target.value;
|
||
renderPlatforms();
|
||
});
|
||
byId("platform-status").addEventListener("change", (event) => {
|
||
state.platformStatus = event.target.value;
|
||
renderPlatforms();
|
||
});
|
||
};
|
||
|
||
const setupTheme = () => {
|
||
const root = document.documentElement;
|
||
let saved = null;
|
||
try {
|
||
saved = localStorage.getItem("quant-os-status-theme");
|
||
} catch (_) {
|
||
saved = null;
|
||
}
|
||
if (saved === "light" || saved === "dark") {
|
||
root.dataset.theme = saved;
|
||
}
|
||
const updateLabel = () => {
|
||
byId("theme-label").textContent = root.dataset.theme === "light" ? "切换深色" : "切换浅色";
|
||
};
|
||
updateLabel();
|
||
byId("theme-toggle").addEventListener("click", () => {
|
||
root.dataset.theme = root.dataset.theme === "light" ? "dark" : "light";
|
||
try {
|
||
localStorage.setItem("quant-os-status-theme", root.dataset.theme);
|
||
} catch (_) {
|
||
// Theme persistence is optional; the page remains functional.
|
||
}
|
||
updateLabel();
|
||
});
|
||
};
|
||
|
||
const setupSectionObserver = () => {
|
||
const links = [...document.querySelectorAll(".rail a")];
|
||
if (!("IntersectionObserver" in window)) return;
|
||
const observer = new IntersectionObserver((entries) => {
|
||
const visible = entries
|
||
.filter((entry) => entry.isIntersecting)
|
||
.sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
|
||
if (!visible) return;
|
||
links.forEach((link) => {
|
||
link.setAttribute("aria-current", link.getAttribute("href") === `#${visible.target.id}` ? "true" : "false");
|
||
});
|
||
}, { rootMargin: "-15% 0px -70% 0px", threshold: [0, 0.2, 0.6] });
|
||
document.querySelectorAll(".audit-section").forEach((section) => observer.observe(section));
|
||
};
|
||
|
||
const validatePublicData = (data) => {
|
||
if (!data || typeof data !== "object") throw new Error("missing public status object");
|
||
if (data.claim?.status !== "NOT_BASELINE_60") throw new Error("unsafe claim status");
|
||
if (data.claim?.releaseVerified !== false || data.claim?.liveReady !== false) {
|
||
throw new Error("unsafe release claim");
|
||
}
|
||
if (data.claim?.gatesPassed !== 0 || data.claim?.gatesTotal !== 10) {
|
||
throw new Error("unexpected gate score");
|
||
}
|
||
if (!Array.isArray(data.gates) || data.gates.some((gate) => gate.status !== "not_passed")) {
|
||
throw new Error("all gates must remain explicitly not_passed");
|
||
}
|
||
};
|
||
|
||
const boot = () => {
|
||
setupTheme();
|
||
setupFilters();
|
||
const data = window.QUANT_OS_PUBLIC_STATUS;
|
||
try {
|
||
validatePublicData(data);
|
||
state.data = data;
|
||
state.evidenceById = new Map((data.evidence || []).map((item) => [item.id, item]));
|
||
renderHeader(data);
|
||
renderLayers(data);
|
||
renderModels(data);
|
||
renderPlatforms();
|
||
renderGates(data);
|
||
renderBundles(data);
|
||
renderActions(data);
|
||
renderFreshness(data);
|
||
renderProvenance(data);
|
||
setupSectionObserver();
|
||
byId("loading-state").hidden = true;
|
||
byId("error-state").hidden = true;
|
||
} catch (error) {
|
||
byId("loading-state").hidden = true;
|
||
byId("error-state").hidden = false;
|
||
console.error("Quant OS public status validation failed:", error);
|
||
}
|
||
};
|
||
|
||
boot();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|