From cbb99de748244421a65f5db0881c57684ca832c5 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Thu, 8 Oct 2026 12:02:22 +0100 Subject: [PATCH] fix: standardize dashboard controls and remove redundant chrome --- agents/conductors/cortex/AGENTS.md | 11 ++++--- agents/conductors/cortex/_cortex.py | 50 ++++------------------------- board/_board.py | 7 ++-- board/_theme.py | 6 +++- docs/board-orchestration.md | 9 +++++- tests/test_board.py | 6 ++-- tests/test_board_theme.py | 3 +- tests/test_cortex_conductor.py | 7 ++-- 8 files changed, 36 insertions(+), 63 deletions(-) diff --git a/agents/conductors/cortex/AGENTS.md b/agents/conductors/cortex/AGENTS.md index 4d769578..7ff4c7c0 100644 --- a/agents/conductors/cortex/AGENTS.md +++ b/agents/conductors/cortex/AGENTS.md @@ -31,7 +31,7 @@ note`). | `checkin [--dry-run \| --apply] [--push \| --no-push] [--project KEY]` | **Where is my science?** | the door — the sequence below, ending in a summary keyed by project; reaches no cluster; exit **1** when the tree does not check | | `census [--json]` | What is the Cortex holding? | per project: status, summary, runs by state, log length, last update; totals (active projects, runs open, runs running); the check-in stamp; the problems `cortex.py check` would report | | `dashboard --check` | Are the committed pages current? | exit 0 current · **1 stale** · 2 no checkout · 3 unreadable tree | -| `dashboard --apply` | — | writes `dashboard.md` + `dashboard.html` + `state.json` — the organ-cockpit feed (`board/_state.py` v1): red on `cortex.py check` problems, yellow while a run is running or the check-in is stale (the page script's 180-min rule, judged at render), items carry `checkin_payload` / `resume_payload`; `--check` ignores its `updated` | +| `dashboard --apply` | — | writes `dashboard.md` + `dashboard.html` + `state.json` — the organ-cockpit feed (`board/_state.py` v1): red on `cortex.py check` problems, yellow while a run is running or the check-in is stale (the feed's 180-min rule, judged at render), items carry `checkin_payload` / `resume_payload`; `--check` ignores its `updated` | | `issue [--project KEY] [--apply]` | What sits at the top of each project's issue? | the fenced ledger block (`cortex.py`'s `issue_block`) per project with an `Issue:`; `--apply` writes it into the issue body through `gh` (replacing the block between the markers, or prepending it); never creates an issue; exit **1** without `gh` | ``` @@ -78,8 +78,8 @@ The page opens on the door: a counts table (`Running`, `Open`, `Projects` — what `board/_board.py` reads for the Brain board's Cortex strip), the **check-in chip** — two lines, because the check-in has two halves that do not run on the same machine: `pyauto-brain cortex pull` on the laptop, then -`pyauto-brain cortex checkin --apply --push` anywhere — and the **last -check-in** stamp under it. Then **Summary**: one row per active project, four +`pyauto-brain cortex checkin --apply --push` anywhere — and the shared +**Last updated / Update** footer. Then **Summary**: one row per active project, four narrow columns (`Project | Running | Open | Last update`) so it fits a phone. Then **Projects**: a `### — ` card per project with a ledger — active first in `projects.yaml` order, then planned/dormant, with the retired @@ -98,8 +98,9 @@ chips anywhere — retiring is `scripts/cortex.py retire`, a typed verb. **`checkin.yaml`** is the one-key file (`refreshed: `) the door writes before rendering. `census()` reads it into `c["checkin"]`; missing means "never checked in", unparseable is a `problems` line. The -stamp means *last check-in*, never last render, and the HTML twin computes -its age on the **viewer's** clock and reddens it once stale. +stamp means *last check-in*, never last render. The cockpit feed keeps its +180-minute check-in freshness rule; the HTML uses the shared panel refresh +footer and omits the old standalone check-in widget. `--check` compares the pages with the generation comment **and** the visible `Last updated` banner stripped, so a re-render on a new date is not drift. diff --git a/agents/conductors/cortex/_cortex.py b/agents/conductors/cortex/_cortex.py index 78b7b3ec..b194d074 100644 --- a/agents/conductors/cortex/_cortex.py +++ b/agents/conductors/cortex/_cortex.py @@ -595,39 +595,11 @@ def render_dashboard(c: dict) -> str: "table.map{width:100%;border-collapse:collapse;font-size:.95em}" "table.map th{text-align:left;color:var(--muted);font-weight:600}" "table.map td,table.map th{border-bottom:1px solid var(--line);padding:.4rem .5rem .4rem 0;vertical-align:top}" - ".checkin{display:flex;gap:.9rem;align-items:center;padding:.9rem 1.2rem;border:2px solid var(--line);border-radius:.6rem;margin:.2rem 0 1.4rem}" - ".checkin .mark{font-size:2rem;line-height:1}" - ".checkin .label{display:block;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}" - ".checkin time{font-size:1.6rem;font-weight:700;font-variant-numeric:tabular-nums;display:block}" - ".checkin .note{font-size:.85rem;color:var(--muted)}" - ".checkin.fresh-ok{border-color:var(--ok);background:color-mix(in srgb,var(--ok) 12%,transparent)}" - ".checkin.fresh-ok .mark{color:var(--ok)}" - ".checkin.fresh-bad{border-color:var(--bad);background:color-mix(in srgb,var(--bad) 12%,transparent)}" - ".checkin.fresh-bad .mark{color:var(--bad)}" ".project h3{font-size:1.35rem;font-weight:700;padding-bottom:.2rem;border-bottom:2px solid var(--accent);letter-spacing:.01em;margin-top:1.6rem}" ".pathchip{display:inline-block;background:var(--accent);color:#fff;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.88em;padding:.12em .5em;border-radius:.3rem;overflow-wrap:anywhere}" "@media(prefers-color-scheme:dark){.pathchip{background:color-mix(in srgb,var(--accent) 55%,#000)}}" ".stale{color:var(--bad);font-weight:600}") -# The page is static, so a stamp is never stale *at render* — it is stale on -# the reader's clock, 3 h later, on a different day. So the age is computed -# on load, here, and nowhere else: the box is neutral until this runs. -_CHECKIN_JS = ( - "(function(){var e=document.getElementById('checkin')," - "b=document.getElementById('checkin-box')," - "m=document.getElementById('checkin-mark')," - "n=document.getElementById('checkin-note');if(!e||!b)return;" - "var t=e.getAttribute('datetime'),d=t?new Date(t):null;" - "if(!d||isNaN(d.getTime())||(Date.now()-d.getTime())/60000>" - f"{CHECKIN_FRESH_MINUTES}){{" - "b.classList.add('fresh-bad');e.classList.add('stale');" - "if(m)m.textContent='✗';" - "if(n)n.textContent=t?'stale, paste the check-in':'never checked in';" - "}else{b.classList.add('fresh-ok');if(m)m.textContent='✓';" - "var a=Math.round((Date.now()-d.getTime())/60000);" - "if(n)n.textContent='fresh · '+(a<60?a+' min':Math.round(a/60)+' h')" - "+' ago';}})();") - def render_dashboard_html(c: dict) -> str: """The one-tap-copy twin GitHub Pages serves — same content, real buttons.""" @@ -656,32 +628,23 @@ def render_dashboard_html(c: dict) -> str: {"label": "Running", "href": "#summary", "count": n["running"]}, {"label": "Open", "href": "#summary", "count": n["open"]}, {"label": "Projects", "href": "#projects", "count": n["active"]}, - {"label": "Check in", "href": "#checkin-box"}, + {"label": "Check in", "href": "#orchestration-cortex"}, ]), orchestration_panel( "cortex", "Check in on the science", "Review projects and runs together, then record what you have learned.", - checkin_payload(c), work_links=work_links, copy_label=CHECKIN_LABEL, organ="cortex", + checkin_payload(c), work_links=work_links, organ="cortex", refreshed_at=c.get("refreshed_at") if not c.get("problems") else None, refresh_url=home + "/actions/workflows/dashboard_refresh.yml" if home else None), ] if home: H.append(f'

' - f'markdown version · ' - "GitHub Page

") + f'markdown version

') if c["problems"]: H += ['

⚠️ The tree does not check — ' "scripts/cortex.py check reports:

", "
    "] H += [f"
  • {_esc(p)}
  • " for p in c["problems"][:10]] H += ["
"] - stamp = c.get("checkin") or "" - H += [f'
' - f'
' - f'Last check-in' - f'' - f'
'] - H += ['

Summary

', '', "" ""] @@ -720,8 +683,7 @@ def render_dashboard_html(c: dict) -> str: footer = boards_footer(dict(_board_links(home, THEME_ORGAN)), THEME_ORGAN) if footer: H.append(footer) - H += [f"", - f"", "", ""] + H += [f"", "", ""] return section_layout("\n".join(H) + "\n") @@ -752,9 +714,9 @@ def _now() -> _dt.datetime: def checkin_stale(stamp: str, now: _dt.datetime | None = None) -> bool: - """The page script's freshness rule (`_CHECKIN_JS`), in Python: a missing + """The cockpit feed's check-in freshness rule: a missing or unparseable stamp, or one older than CHECKIN_FRESH_MINUTES, is stale. - The page judges on the reader's clock at load; the feed judges at render.""" + The feed judges at render; the panel refresh clock is independent.""" if not stamp: return True try: diff --git a/board/_board.py b/board/_board.py index f5470a92..6850f188 100755 --- a/board/_board.py +++ b/board/_board.py @@ -1612,13 +1612,10 @@ def render_html(data): # page. `–` where a source was unreachable: an absent count is never a # zero here, the same contract the rows keep. # The sibling boards' header line: the markdown twin (written beside - # index.html by --apply, so the relative href resolves on Pages) and the - # way back to the repository front door on github.com. + # index.html by --apply, so the relative href resolves on Pages). if data.get("org") and data.get("repo"): - gh = (f'https://github.com/{data["org"]}/{data["repo"]}' - "/blob/main/README.md") H.append('

markdown ' - f'version · GitHub Page

') + f'version

') H.append("

⌨ Morning sync (local)

") H.append(_row( "Sync every repo to main + clean generated cruft — run in a terminal " diff --git a/board/_theme.py b/board/_theme.py index 792a48cf..0df49124 100644 --- a/board/_theme.py +++ b/board/_theme.py @@ -929,8 +929,12 @@ def orchestration_panel(key, title, description, prompt, *, work_links=(), # Labels are also plain text in the prompt; disallow line injection. if not label.strip() or any(c in label for c in "\r\n"): raise ValueError("Work destination labels must be nonempty, single-line text") + # Repository buttons use the destination's name; companion surfaces + # such as the organization Community Hub keep their descriptive label. + parts = parsed.path.strip("/").split("/") + display_label = parts[1] if len(parts) >= 2 and parts[0] not in {"orgs", "users"} else label links.append(f'' - f'{_html.escape(label)}') + f'{_html.escape(display_label)}') context.append(f"- {label}: {url}") base = portable_prompt(prompt).replace("\r\n", "\n").replace("\r", "\n") if context: diff --git a/docs/board-orchestration.md b/docs/board-orchestration.md index fcb0b27a..1b369dda 100644 --- a/docs/board-orchestration.md +++ b/docs/board-orchestration.md @@ -27,7 +27,11 @@ truncate words. Omit explanatory subtitles and preserve work links/copy controls `work_links` is an ordered list of mappings with `label` and `href`. Destinations must be HTTPS GitHub links. These owner-supplied links appear beside the controls -and are appended under **Work on GitHub** in the portable prompt. They are fixed +and are appended under **Work on GitHub** in the portable prompt. Repository +buttons display the repository name from the destination URL, without the owner +prefix or “Open”/“repository” filler. Non-repository companion destinations keep +their supplied labels; portable prompt metadata retains its original labels. +Every primary panel copy button uses **Copy check-in prompt**. They are fixed metadata; typing a focus does not rewrite them. Avoid putting the same URL list in the base prompt as well. Missing metadata displays an explicit unavailable message, never an invented destination. @@ -61,6 +65,9 @@ Different panels must not overwrite one another's input, preview or feedback. ## Last updated footer +Omit redundant **GitHub Page** links and the legacy standalone Cortex +last-check-in/stale widget. Keep underlying check-in records and feed semantics. + Every panel has the same small footer beneath the copy controls: **Read the prompt** on the left, **Last updated …** and **↻ Update** on the right. It wraps below the preview control on narrow screens. Brain owns the markup, typography, diff --git a/tests/test_board.py b/tests/test_board.py index 4edf6202..fc97cb4f 100644 --- a/tests/test_board.py +++ b/tests/test_board.py @@ -541,11 +541,9 @@ def test_html_is_self_contained_with_one_tap_payloads(tmp_path): assert 'data-cmd="bash PyAutoBrain/bin/morning.sh"' in page # The doors roster is on the page. assert 'data-cmd="Use the intake skill."' in page - # The header line every sibling board carries: the markdown twin and the - # way back to the repository front door on github.com. + # Keep the Markdown source without the redundant repository link. assert 'GitHub Page') in page + assert 'GitHub Page' not in page # --------------------------------------------------------------- the look -- diff --git a/tests/test_board_theme.py b/tests/test_board_theme.py index eba15f4e..3f660a8f 100644 --- a/tests/test_board_theme.py +++ b/tests/test_board_theme.py @@ -468,11 +468,12 @@ def test_orchestration_panel_keeps_work_links_in_visible_and_portable_context(): work_links=[{'label': 'Open work repo', 'href': 'https://github.com/Example/Work'}, {'label': 'Community hub', 'href': 'https://github.com/orgs/Example/discussions'}]) assert 'Review <work>' in page and 'A & B' not in page - assert 'Open work repo' in page + assert 'Work' in page preview = unescape(re.search(r'data-orchestration-prompt[^>]*>(.*?)', page, re.S)[1]) assert preview == ('Use the board skill. check\n\nWork on GitHub:\n' '- Open work repo: https://github.com/Example/Work\n' '- Community hub: https://github.com/orgs/Example/discussions') + assert 'Community hub' in page assert 'readonly' in page and 'aria-live="polite"' in page diff --git a/tests/test_cortex_conductor.py b/tests/test_cortex_conductor.py index 6096b604..4adcf612 100644 --- a/tests/test_cortex_conductor.py +++ b/tests/test_cortex_conductor.py @@ -289,8 +289,11 @@ def test_the_html_twin_wears_the_theme_with_real_copy_buttons(skeleton): assert "On the laptop, use the Cortex pull procedure" in html assert "Follow the Cortex check-in procedure to refresh the board" in html assert "Submit compute only when I explicitly ask" in html - assert '' in html - assert "fresh-bad" in html and _cortex._CHECKIN_JS in html + assert 'id="checkin-box"' not in html + assert 'stale, paste the check-in' not in html + assert 'Copy check-in prompt' in html + assert 'data-freshness-stamp' in html + assert 'GitHub Page' not in html assert "1Running" in html assert "1Open" in html assert "2Projects" in html
ProjectRunningOpenLast update