generated from mathias/template-go-web
feat(atlas): UX — overview rail + gate glyphs + pill reconcile (#3,#4,#5)
Closes the UX sprint's authored layer. #3 Horizontal-scroll blindness → an always-visible "PIPELINE" overview rail: 9 colour-coded chips (00 Notice → 08 Learn) showing the whole shape at a glance, each click-to-scroll to its stage. First-timers now see the arc + that more exists. #4 Real gate glyph — 🔒 on the two checkpoint transitions (human @04, CI @06), desktop spine + mobile rows. #5 Reconcile legend with Plain: decorative node pills hidden in Plain, so colour is reserved for live status (green/amber/coral) — exactly what the legend keys. (#6 attached chips/grammar: the question-vs-statement label mix is meaningful — decisions vs milestones — kept; SVG chip background skipped as low-value.) New Stage.short (guarded by JSON validity via existing tests). build/vet/lint(0)/ test green; desktop Plain screenshot-verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,49 +7,49 @@
|
|||||||
],
|
],
|
||||||
"ns": "Tailscale mesh · ns: ai-stack · supervisor(→brain) · gitea-mcp · infra-mcp · council",
|
"ns": "Tailscale mesh · ns: ai-stack · supervisor(→brain) · gitea-mcp · infra-mcp · council",
|
||||||
"stages": [
|
"stages": [
|
||||||
{"no":"STAGE 00","title":"Signals","plain_title":"Notice what's happening","plain":"New ideas and developments worth reacting to are collected — mostly an automated daily/weekly scan of AI news, plus things saved by hand.","path":"→ mathias/signals",
|
{"no":"STAGE 00","short":"Notice","title":"Signals","plain_title":"Notice what's happening","plain":"New ideas and developments worth reacting to are collected — mostly an automated daily/weekly scan of AI news, plus things saved by hand.","path":"→ mathias/signals",
|
||||||
"trans_label":"Does it matter to us?","trans":"A raw signal only advances if it connects to something we actually care about. Most captured signals stop here; the few that touch the mission get pulled up against a goal.","nodes":[
|
"trans_label":"Does it matter to us?","trans":"A raw signal only advances if it connects to something we actually care about. Most captured signals stop here; the few that touch the mission get pulled up against a goal.","nodes":[
|
||||||
{"t":"Applied AI Radar","plain_t":"Automated news scan","plain":"An automated scan reads AI news every day (and deeper every week) and keeps only claims backed by a real paper, benchmark, code, or named lab.","d":"Daily Tier-1 + weekly Tier-2 deep pass. Verified-primary bar (paper/benchmark/code/named-lab).","tags":["cron · daily/weekly","→ signals #1–26+"]},
|
{"t":"Applied AI Radar","plain_t":"Automated news scan","plain":"An automated scan reads AI news every day (and deeper every week) and keeps only claims backed by a real paper, benchmark, code, or named lab.","d":"Daily Tier-1 + weekly Tier-2 deep pass. Verified-primary bar (paper/benchmark/code/named-lab).","tags":["cron · daily/weekly","→ signals #1–26+"]},
|
||||||
{"t":"Manual capture","plain_t":"Saved by hand","plain":"Anything interesting spotted by hand gets saved into the same inbox.","d":"claude.ai strategic drop · brain capture tool.","tags":["ad-hoc"]},
|
{"t":"Manual capture","plain_t":"Saved by hand","plain":"Anything interesting spotted by hand gets saved into the same inbox.","d":"claude.ai strategic drop · brain capture tool.","tags":["ad-hoc"]},
|
||||||
{"t":"Aspirational surfaces","plain_t":"Not built yet","plain":"Planned but not built yet: sending ideas in by Telegram, voice, or a URL.","pill":"var(--dim)","d":"Telegram / voice / URL → inbox. NOT built.","tags":["gap"]}
|
{"t":"Aspirational surfaces","plain_t":"Not built yet","plain":"Planned but not built yet: sending ideas in by Telegram, voice, or a URL.","pill":"var(--dim)","d":"Telegram / voice / URL → inbox. NOT built.","tags":["gap"]}
|
||||||
]},
|
]},
|
||||||
{"no":"STAGE 01","cls":"telos","title":"TELOS","plain_title":"Why we're here","plain":"The mission, goals, and problems we're actually trying to solve live here — every piece of work downstream has to trace back to one of these goals.","path":"wiki/telos/",
|
{"no":"STAGE 01","short":"Why","cls":"telos","title":"TELOS","plain_title":"Why we're here","plain":"The mission, goals, and problems we're actually trying to solve live here — every piece of work downstream has to trace back to one of these goals.","path":"wiki/telos/",
|
||||||
"trans_label":"Worth a session?","trans":"A goal or problem on the board becomes the seed for a design session when it's decided worth working on now. The goal is the input the session must trace back to.","nodes":[
|
"trans_label":"Worth a session?","trans":"A goal or problem on the board becomes the seed for a design session when it's decided worth working on now. The goal is the input the session must trace back to.","nodes":[
|
||||||
{"t":"Intention substrate","plain_t":"The goal board","plain":"The master list of mission, goals, problems, and current status — the yardstick everything downstream is measured against.","pill":"var(--violet)","d":"Mission · goals · problems · strategies · status. Every downstream item traces to a goal.","tags":["brain_query wing=telos"]}
|
{"t":"Intention substrate","plain_t":"The goal board","plain":"The master list of mission, goals, problems, and current status — the yardstick everything downstream is measured against.","pill":"var(--violet)","d":"Mission · goals · problems · strategies · status. Every downstream item traces to a goal.","tags":["brain_query wing=telos"]}
|
||||||
]},
|
]},
|
||||||
{"no":"STAGE 02","title":"Strategic session","plain_title":"Think it through","plain":"A human and AI models work out what to do and why, debating hard calls and writing down the decision and what \"done\" will mean.","path":"claude.ai frontier + brain MCP",
|
{"no":"STAGE 02","short":"Think","title":"Strategic session","plain_title":"Think it through","plain":"A human and AI models work out what to do and why, debating hard calls and writing down the decision and what \"done\" will mean.","path":"claude.ai frontier + brain MCP",
|
||||||
"trans_label":"Decision reached","trans":"It advances only when the thinking converges on a decision and is written down as a concrete, testable specification — not while the answer is still open.","nodes":[
|
"trans_label":"Decision reached","trans":"It advances only when the thinking converges on a decision and is written down as a concrete, testable specification — not while the answer is still open.","nodes":[
|
||||||
{"t":"Design · ADRs · specs","plain_t":"Decide the approach","plain":"A human and a top-tier AI model figure out the approach and write down the decision plus what a finished result must prove.","d":"Human + frontier model. ISC acceptance criteria written here.","tags":["Define / converge"]},
|
{"t":"Design · ADRs · specs","plain_t":"Decide the approach","plain":"A human and a top-tier AI model figure out the approach and write down the decision plus what a finished result must prove.","d":"Human + frontier model. ISC acceptance criteria written here.","tags":["Define / converge"]},
|
||||||
{"t":"🏛️ LLM Council","plain_t":"AI review panel","plain":"For hard calls, several AI models answer independently, anonymously critique each other, and a \"chair\" model synthesises one verdict — reducing any single model's bias.","cls":"council","pill":"var(--violet)","d":"fan-out → anonymous cross-review → chairman synth. glm-4.7-flash · qwen36-35b · gemma4-31b (chair).","tags":["hard strategic Q","chat.d-ma.be"]},
|
{"t":"🏛️ LLM Council","plain_t":"AI review panel","plain":"For hard calls, several AI models answer independently, anonymously critique each other, and a \"chair\" model synthesises one verdict — reducing any single model's bias.","cls":"council","pill":"var(--violet)","d":"fan-out → anonymous cross-review → chairman synth. glm-4.7-flash · qwen36-35b · gemma4-31b (chair).","tags":["hard strategic Q","chat.d-ma.be"]},
|
||||||
{"t":"Autoresearch Council","plain_t":"Research review panel","plain":"A parallel version of the same review that vets research findings before they're allowed through.","cls":"council","pill":"var(--violet)","d":"Sibling pipe — ratifies research before the gate.","tags":["proposed: → standalone svc"]}
|
{"t":"Autoresearch Council","plain_t":"Research review panel","plain":"A parallel version of the same review that vets research findings before they're allowed through.","cls":"council","pill":"var(--violet)","d":"Sibling pipe — ratifies research before the gate.","tags":["proposed: → standalone svc"]}
|
||||||
]},
|
]},
|
||||||
{"no":"STAGE 03","title":"Spec → Gitea issue","plain_title":"Write the work order","plain":"The decision is turned into a precise, self-contained work order an AI agent can execute unsupervised — with a pass/fail definition of done, a risk rating, and a tamper-proof seal.","path":"agent-ready contract",
|
{"no":"STAGE 03","short":"Write order","title":"Spec → Gitea issue","plain_title":"Write the work order","plain":"The decision is turned into a precise, self-contained work order an AI agent can execute unsupervised — with a pass/fail definition of done, a risk rating, and a tamper-proof seal.","path":"agent-ready contract",
|
||||||
"trans_label":"Sealed & agent-ready","trans":"Advances to the gate only when the spec is a complete contract: a pass/fail test, a risk tier, a regulatory note, no open human dependencies, one embedded Oath, and a valid cryptographic signature. A malformed or unsigned order fails closed and never reaches the gate.","nodes":[
|
"trans_label":"Sealed & agent-ready","trans":"Advances to the gate only when the spec is a complete contract: a pass/fail test, a risk tier, a regulatory note, no open human dependencies, one embedded Oath, and a valid cryptographic signature. A malformed or unsigned order fails closed and never reaches the gate.","nodes":[
|
||||||
{"t":"Contract enforced","plain_t":"The work-order rules","plain":"The work order must have a clear pass/fail test, a risk rating, a regulatory-risk note, and no unfinished human dependencies before it counts as agent-ready.","d":"Binary ISC · declared risk tier · reg-risk assessment · no open human deps.","tags":["LOW / MED / HIGH"]},
|
{"t":"Contract enforced","plain_t":"The work-order rules","plain":"The work order must have a clear pass/fail test, a risk rating, a regulatory-risk note, and no unfinished human dependencies before it counts as agent-ready.","d":"Binary ISC · declared risk tier · reg-risk assessment · no open human deps.","tags":["LOW / MED / HIGH"]},
|
||||||
{"t":"Admission controller","plain_t":"Tamper-proof seal","plain":"The work order is cryptographically signed when created, so any later tampering is detectable and the eventual change can be checked against it.","d":"Ed25519-sign issue body at creation (#36). Verify sig + PR alignment at infra boundary.","tags":["chain of custody"]},
|
{"t":"Admission controller","plain_t":"Tamper-proof seal","plain":"The work order is cryptographically signed when created, so any later tampering is detectable and the eventual change can be checked against it.","d":"Ed25519-sign issue body at creation (#36). Verify sig + PR alignment at infra boundary.","tags":["chain of custody"]},
|
||||||
{"t":"⚖️ var-go Oath","plain_t":"Definition of done","plain":"A machine-checkable \"definition of done\" is embedded in the work order — exactly one, or the order is rejected — later used to prove the result actually meets the spec.","cls":"oath","pill":"var(--gold)","d":"Acceptance contract embedded in the issue as a var fenced block. Exactly one — zero/multiple fail closed. Prose → typed steps; failures anchored to byte spans.","tags":["swedsl · var-go","defined here → enforced @06"]}
|
{"t":"⚖️ var-go Oath","plain_t":"Definition of done","plain":"A machine-checkable \"definition of done\" is embedded in the work order — exactly one, or the order is rejected — later used to prove the result actually meets the spec.","cls":"oath","pill":"var(--gold)","d":"Acceptance contract embedded in the issue as a var fenced block. Exactly one — zero/multiple fail closed. Prose → typed steps; failures anchored to byte spans.","tags":["swedsl · var-go","defined here → enforced @06"]}
|
||||||
]},
|
]},
|
||||||
{"no":"STAGE 04","cls":"gate","title":"Human dispatch gate","plain_title":"Human says go","plain":"A person reviews the work order and its risk and decides whether to release it — the one and only checkpoint where work does not move on its own.","path":"the only checkpoint",
|
{"no":"STAGE 04","short":"Human go","cls":"gate","title":"Human dispatch gate","plain_title":"Human says go","plain":"A person reviews the work order and its risk and decides whether to release it — the one and only checkpoint where work does not move on its own.","path":"the only checkpoint",
|
||||||
"trans_label":"A human said go","trans":"The hard stop. Nothing crosses automatically — a person must review the plan and risk and explicitly release it, and the repo must be on the allow-list, before any agent starts. This is the single human checkpoint in the whole pipeline.","nodes":[
|
"trans_label":"A human said go","trans":"The hard stop. Nothing crosses automatically — a person must review the plan and risk and explicitly release it, and the repo must be on the allow-list, before any agent starts. This is the single human checkpoint in the whole pipeline.","nodes":[
|
||||||
{"t":"Human triggers execution","plain_t":"The go button","plain":"A person confirms the plan and its risk level, then releases the work — nothing runs until they do.","cls":"gateway","pill":"var(--amber)","d":"Ratify proposed-plan + risk tier, then dispatch.","gate":true},
|
{"t":"Human triggers execution","plain_t":"The go button","plain":"A person confirms the plan and its risk level, then releases the work — nothing runs until they do.","cls":"gateway","pill":"var(--amber)","d":"Ratify proposed-plan + risk tier, then dispatch.","gate":true},
|
||||||
{"t":"Session-Dispatch bridge","plain_t":"Hand-off to agents","plain":"The approval flips a switch that hands the signed work order over to the agents to start execution.","cls":"bridge","pill":"var(--blue)","d":"claude.ai MCP → gitea:workflow_run_trigger → cad-dispatch.yml → agentsquad. The final design→execution bridge.","tags":["workflow_dispatch"]}
|
{"t":"Session-Dispatch bridge","plain_t":"Hand-off to agents","plain":"The approval flips a switch that hands the signed work order over to the agents to start execution.","cls":"bridge","pill":"var(--blue)","d":"claude.ai MCP → gitea:workflow_run_trigger → cad-dispatch.yml → agentsquad. The final design→execution bridge.","tags":["workflow_dispatch"]}
|
||||||
]},
|
]},
|
||||||
{"no":"STAGE 05","cls":"exec","title":"Execute · agentsquad","plain_title":"Agents do the work","plain":"AI agents actually build the thing — one writes, a second independent one reviews it to avoid marking its own homework — and every step is logged for the audit trail.","path":"koala · cmd/agentsquad-serve",
|
{"no":"STAGE 05","short":"Build","cls":"exec","title":"Execute · agentsquad","plain_title":"Agents do the work","plain":"AI agents actually build the thing — one writes, a second independent one reviews it to avoid marking its own homework — and every step is logged for the audit trail.","path":"koala · cmd/agentsquad-serve",
|
||||||
"trans_label":"Change proposed","trans":"Advances when the agents finish and open a proposed change (a PR) with its audit log attached. Until there's a concrete change to test, nothing moves.","nodes":[
|
"trans_label":"Change proposed","trans":"Advances when the agents finish and open a proposed change (a PR) with its audit log attached. Until there's a concrete change to test, nothing moves.","nodes":[
|
||||||
{"t":"Task API","plain_t":"Start a job","plain":"A request kicks off a job and hands back an id you can poll for progress.","pill":"var(--coral)","d":"POST /tasks → job id · GET /tasks/{id}. taskqueue + serve (v0.12+).","tags":["single agentsquad.yaml"]},
|
{"t":"Task API","plain_t":"Start a job","plain":"A request kicks off a job and hands back an id you can poll for progress.","pill":"var(--coral)","d":"POST /tasks → job id · GET /tasks/{id}. taskqueue + serve (v0.12+).","tags":["single agentsquad.yaml"]},
|
||||||
{"t":"Executor + reviewer loop","plain_t":"Build + independent review","plain":"One agent does the work; a second, independent agent on a different model reviews it — so nothing marks its own homework.","cls":"win","pill":"var(--coral)","d":"ADK Go + LiteLLM. Frontier models (local qwen spirals). Reviewer on distinct tier — echo-chamber prevention.","risk":true},
|
{"t":"Executor + reviewer loop","plain_t":"Build + independent review","plain":"One agent does the work; a second, independent agent on a different model reviews it — so nothing marks its own homework.","cls":"win","pill":"var(--coral)","d":"ADK Go + LiteLLM. Frontier models (local qwen spirals). Reviewer on distinct tier — echo-chamber prevention.","risk":true},
|
||||||
{"t":"dma-cli · routing + scope","plain_t":"Router & guardrails","plain":"A router sends each agent to the right AI backend and enforces what it is and isn't allowed to touch, with a confirmation gate as a guardrail.","cls":"bridge","pill":"var(--blue)","d":"Harness-config arm: routes agents to the right LLM backend. Three-layer scope policy + confirmation gate = CAD guardrail.","tags":["backend routing","scope guardrail"]},
|
{"t":"dma-cli · routing + scope","plain_t":"Router & guardrails","plain":"A router sends each agent to the right AI backend and enforces what it is and isn't allowed to touch, with a confirmation gate as a guardrail.","cls":"bridge","pill":"var(--blue)","d":"Harness-config arm: routes agents to the right LLM backend. Three-layer scope policy + confirmation gate = CAD guardrail.","tags":["backend routing","scope guardrail"]},
|
||||||
{"t":"assessor-loop ledger","plain_t":"Audit log","plain":"Every step is recorded in a tamper-evident log so the whole run can be audited afterwards.","d":"Attestation ledger (audit trail) + brain session_log on completion.","tags":["audit package"]}
|
{"t":"assessor-loop ledger","plain_t":"Audit log","plain":"Every step is recorded in a tamper-evident log so the whole run can be audited afterwards.","d":"Attestation ledger (audit trail) + brain session_log on completion.","tags":["audit package"]}
|
||||||
]},
|
]},
|
||||||
{"no":"STAGE 06","title":"PR → CI","plain_title":"Automatic quality checks","plain":"The proposed change is run through automated tests and safety checks — including a check that it actually satisfies the work order's definition of done — and only a clean pass lets it continue.","path":"Gitea Actions · cd.yml (live)","generate":"ci-jobs",
|
{"no":"STAGE 06","short":"Check","title":"PR → CI","plain_title":"Automatic quality checks","plain":"The proposed change is run through automated tests and safety checks — including a check that it actually satisfies the work order's definition of done — and only a clean pass lets it continue.","path":"Gitea Actions · cd.yml (live)","generate":"ci-jobs",
|
||||||
"trans_label":"All checks green","trans":"Advances only if every automated check passes — tests, linters, security scan, and the Oath check proving it meets the original work order. Any red gate stops it here; a passing reviewer is not enough to override a failed Oath.","nodes":[
|
"trans_label":"All checks green","trans":"Advances only if every automated check passes — tests, linters, security scan, and the Oath check proving it meets the original work order. Any red gate stops it here; a passing reviewer is not enough to override a failed Oath.","nodes":[
|
||||||
{"t":"Automated checks","plain_t":"Quality checks","plain":"Tests, linters, a security scan, plus a check that the change actually meets the work order — all must pass to continue.","d":"go test · vet · lint · govulncheck + var-go/oath gate.","tags":["green = proceed"]}
|
{"t":"Automated checks","plain_t":"Quality checks","plain":"Tests, linters, a security scan, plus a check that the change actually meets the work order — all must pass to continue.","d":"go test · vet · lint · govulncheck + var-go/oath gate.","tags":["green = proceed"]}
|
||||||
]},
|
]},
|
||||||
{"no":"STAGE 07","cls":"cd","title":"CD → pod","plain_title":"Ship it","plain":"Once everything is green, the change is deployed automatically to the live server — with the rule that merging code alone doesn't ship it; the release has to be pointed at the new version.","path":"Flux GitOps → k3s","generate":"deploy-state",
|
{"no":"STAGE 07","short":"Ship","cls":"cd","title":"CD → pod","plain_title":"Ship it","plain":"Once everything is green, the change is deployed automatically to the live server — with the rule that merging code alone doesn't ship it; the release has to be pointed at the new version.","path":"Flux GitOps → k3s","generate":"deploy-state",
|
||||||
"trans_label":"It's live","trans":"Once the new version is actually running on the server, the deployed outcome becomes the input to scoring. Advancing means shipped and observable, not just merged.","nodes":[
|
"trans_label":"It's live","trans":"Once the new version is actually running on the server, the deployed outcome becomes the input to scoring. Advancing means shipped and observable, not just merged.","nodes":[
|
||||||
{"t":"Deploy on green","plain_t":"Auto-deploy when green","plain":"When all checks pass, the release system rolls the new version onto the live server automatically — but only once the release is pointed at that version (merging code alone doesn't ship it).","pill":"var(--green)","d":"Flux reconciles image → k3s pod on koala. Push ≠ deploy: bump tag in mathias/infra.","tags":["ntfy on deploy"]}
|
{"t":"Deploy on green","plain_t":"Auto-deploy when green","plain":"When all checks pass, the release system rolls the new version onto the live server automatically — but only once the release is pointed at that version (merging code alone doesn't ship it).","pill":"var(--green)","d":"Flux reconciles image → k3s pod on koala. Push ≠ deploy: bump tag in mathias/infra.","tags":["ntfy on deploy"]}
|
||||||
]},
|
]},
|
||||||
{"no":"STAGE 08","cls":"telos","title":"Loop back","plain_title":"Did it work?","plain":"The result is scored against the goal that started it and fed back into the mission board, so the next round of planning learns from what shipped.","path":"→ TELOS (feedback bus)",
|
{"no":"STAGE 08","short":"Learn","cls":"telos","title":"Loop back","plain_title":"Did it work?","plain":"The result is scored against the goal that started it and fed back into the mission board, so the next round of planning learns from what shipped.","path":"→ TELOS (feedback bus)",
|
||||||
"trans_label":"What did we learn?","trans":"The scored outcome flows back into the mission board so goals, problems, and priorities update — the loop that makes the pipeline a cycle rather than a line. Partly manual today; an explicit improvement target.","nodes":[
|
"trans_label":"What did we learn?","trans":"The scored outcome flows back into the mission board so goals, problems, and priorities update — the loop that makes the pipeline a cycle rather than a line. Partly manual today; an explicit improvement target.","nodes":[
|
||||||
{"t":"Close the loop","plain_t":"Score & feed back","plain":"The outcome is scored against the goal that started it and written back to the mission board, so future planning learns from what actually shipped.","pill":"var(--violet)","d":"session_log + attestation → brain. Score deploy outcome vs originating goal. (arc partly manual — improvement target.)","tags":["continuous"]}
|
{"t":"Close the loop","plain_t":"Score & feed back","plain":"The outcome is scored against the goal that started it and written back to the mission board, so future planning learns from what actually shipped.","pill":"var(--violet)","d":"session_log + attestation → brain. Score deploy outcome vs originating goal. (arc partly manual — improvement target.)","tags":["continuous"]}
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type Node struct {
|
|||||||
// Nodes are derived from a live source at Build time.
|
// Nodes are derived from a live source at Build time.
|
||||||
type Stage struct {
|
type Stage struct {
|
||||||
No string `json:"no"`
|
No string `json:"no"`
|
||||||
|
Short string `json:"short,omitempty"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
PlainTitle string `json:"plain_title,omitempty"`
|
PlainTitle string `json:"plain_title,omitempty"`
|
||||||
Plain string `json:"plain,omitempty"`
|
Plain string `json:"plain,omitempty"`
|
||||||
|
|||||||
@@ -86,6 +86,19 @@
|
|||||||
.legend .lg{display:inline-flex;align-items:center;gap:6px}
|
.legend .lg{display:inline-flex;align-items:center;gap:6px}
|
||||||
.legend .lg i{width:11px;height:11px;border-radius:3px;display:inline-block;border:1px solid rgba(0,0,0,.35)}
|
.legend .lg i{width:11px;height:11px;border-radius:3px;display:inline-block;border:1px solid rgba(0,0,0,.35)}
|
||||||
.legend .dash{width:18px;border-top:2px dashed var(--violet);display:inline-block}
|
.legend .dash{width:18px;border-top:2px dashed var(--violet);display:inline-block}
|
||||||
|
/* overview rail — see the whole 9-stage shape + jump to any stage */
|
||||||
|
.rail{display:flex;gap:4px;flex-wrap:wrap;align-items:center;
|
||||||
|
padding:8px 22px;border-bottom:1px solid var(--line);background:var(--panel)}
|
||||||
|
.rail .lbl{color:var(--dim);letter-spacing:1.5px;margin-right:4px;font-size:11px}
|
||||||
|
.railchip{font:inherit;font-size:11px;cursor:pointer;color:var(--ink);
|
||||||
|
background:var(--panel2);border:1px solid var(--line);border-radius:6px;padding:4px 9px}
|
||||||
|
.railchip:hover{border-color:var(--blue)}
|
||||||
|
.railchip b{color:var(--dim);font-weight:600;margin-right:3px}
|
||||||
|
.railchip.gate{border-color:rgba(245,185,66,.5)} .railchip.telos{border-color:rgba(155,140,255,.5)}
|
||||||
|
.railchip.exec{border-color:rgba(255,122,92,.5)} .railchip.cd{border-color:rgba(74,208,122,.5)}
|
||||||
|
.railarr{color:var(--dim);font-size:10px}
|
||||||
|
/* Plain view: drop decorative node pills so colour is reserved for live status (keyed in the legend) */
|
||||||
|
body.plain .node .pill{display:none}
|
||||||
|
|
||||||
.scroll{overflow-x:auto;padding:24px 22px 20px}
|
.scroll{overflow-x:auto;padding:24px 22px 20px}
|
||||||
.track{position:relative;display:flex;align-items:flex-start;min-width:max-content}
|
.track{position:relative;display:flex;align-items:flex-start;min-width:max-content}
|
||||||
@@ -167,6 +180,7 @@
|
|||||||
<span class="lg"><i style="background:var(--gold)"></i>governance gate — must pass to advance</span>
|
<span class="lg"><i style="background:var(--gold)"></i>governance gate — must pass to advance</span>
|
||||||
<span class="lg"><span class="dash"></span> feedback loop · partly manual</span>
|
<span class="lg"><span class="dash"></span> feedback loop · partly manual</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="rail mono" id="rail"></div>
|
||||||
|
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
<div class="track" id="track">
|
<div class="track" id="track">
|
||||||
@@ -239,10 +253,24 @@ function renderAtlas(){
|
|||||||
if(s.trans_label){
|
if(s.trans_label){
|
||||||
const tr=document.createElement('div');
|
const tr=document.createElement('div');
|
||||||
tr.className='trans-row'+((idx===4||idx===6)?' trans-row-gate':'');
|
tr.className='trans-row'+((idx===4||idx===6)?' trans-row-gate':'');
|
||||||
tr.innerHTML=`<span class="tr-lbl">${s.trans_label}</span>${s.trans?' '+s.trans:''}`;
|
tr.innerHTML=`<span class="tr-lbl">${(idx===4||idx===6)?'🔒 ':''}${s.trans_label}</span>${s.trans?' '+s.trans:''}`;
|
||||||
track.appendChild(tr);
|
track.appendChild(tr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
renderRail();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderRail(){
|
||||||
|
const rail=document.getElementById('rail');
|
||||||
|
rail.innerHTML='<span class="lbl">PIPELINE</span>';
|
||||||
|
STAGES.forEach((s,i)=>{
|
||||||
|
const c=document.createElement('button');
|
||||||
|
c.className='railchip'+(s.cls?' '+s.cls:'');
|
||||||
|
c.innerHTML=`<b>${(s.no||'').replace('STAGE ','')}</b>${s.short||s.plain_title||s.title}`;
|
||||||
|
c.onclick=()=>{ if(stageEls[i]) stageEls[i].scrollIntoView({behavior:'smooth',inline:'center',block:'nearest'}); };
|
||||||
|
rail.appendChild(c);
|
||||||
|
if(i<STAGES.length-1){const a=document.createElement('span');a.className='railarr';a.textContent='→';rail.appendChild(a);}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTimeline(){
|
function renderTimeline(){
|
||||||
@@ -293,7 +321,7 @@ function build(){
|
|||||||
t.setAttribute('x',(cs[i]+cs[i+1])/2);t.setAttribute('y',RAILY-9);
|
t.setAttribute('x',(cs[i]+cs[i+1])/2);t.setAttribute('y',RAILY-9);
|
||||||
t.setAttribute('text-anchor','middle');
|
t.setAttribute('text-anchor','middle');
|
||||||
t.setAttribute('class',gate?'translabel translabel-gate':'translabel');
|
t.setAttribute('class',gate?'translabel translabel-gate':'translabel');
|
||||||
t.textContent=(gate?'▸ ':'')+s.trans_label;
|
t.textContent=(gate?'🔒 ':'')+s.trans_label;
|
||||||
const ttl=document.createElementNS('http://www.w3.org/2000/svg','title');
|
const ttl=document.createElementNS('http://www.w3.org/2000/svg','title');
|
||||||
ttl.textContent=s.trans||''; t.appendChild(ttl);
|
ttl.textContent=s.trans||''; t.appendChild(ttl);
|
||||||
tg.appendChild(t);
|
tg.appendChild(t);
|
||||||
|
|||||||
Reference in New Issue
Block a user