-
Notifications
You must be signed in to change notification settings - Fork 0
Add cross-project dashboard surface audit and Ops Hub v2 build spec #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+705
−0
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,324 @@ | ||
| # Cross-Project Dashboard Surface Audit — 2026-08-18 | ||
|
|
||
| > [!IMPORTANT] | ||
| > **Read-only audit.** Nothing was archived, unlinked, deleted, de-indexed, or | ||
| > republished. Every remediation below is gated behind explicit approval | ||
| > (see [Remediation bundles](#remediation-bundles)). | ||
|
|
||
| ## Scope | ||
|
|
||
| Every historical surface that has, at some point, tried to answer *"what projects | ||
| exist and what state are they in"*: cross-project dashboards, command centers, | ||
| Ops Hub, Code Dashboard, the project manifest, and the public portfolio hub. | ||
|
|
||
| Each artifact is classified as **preserve**, **migrate**, **archive**, **unlink**, | ||
| or **remove from public**. | ||
|
|
||
| ## Publication boundary applied to this document | ||
|
|
||
| `DaveHomeAssist/code-dashboard` is a **public** repository. Since the central | ||
| finding of this audit is that internal operations material leaked onto public | ||
| infrastructure, publishing an unredacted inventory here would reproduce the exact | ||
| defect being reported. This document therefore contains **only facts already | ||
| public**: anonymous HTTP crawl results, the contents of the already-public | ||
| `project-manifest.json`, and architecture description. | ||
|
|
||
| Deliberately excluded: workspace page titles/URLs/IDs, local filesystem paths, | ||
| private project identifiers, run IDs, and client-engagement detail. Where an | ||
| internal source is cited it is referred to by **role**, not by name — e.g. | ||
| "the dashboard standards governance page". The unredacted inventory belongs in a | ||
| private repository. | ||
|
|
||
| ## Method | ||
|
|
||
| | Evidence class | How it was obtained | Trust | | ||
| |---|---|---| | ||
| | HTTP status, redirects, robots meta, page `<head>` | Anonymous `curl` against the live host, 2026-08-18 | **Confirmed** | | ||
| | Sitemap contents | `GET /sitemap.xml` | **Confirmed** | | ||
| | Public project inventory | `GET /project-manifest.json` | **Confirmed** | | ||
| | Hub rendering logic | Read of the served hub HTML | **Confirmed** | | ||
| | Repository visibility | GitHub API | **Confirmed** | | ||
| | Dashboard lineage & design intent | Internal workspace records | **Reported** — not independently reproducible here | | ||
|
|
||
| Not available, and therefore **not** asserted anywhere in this document: Search | ||
| Console, analytics, CrUX/Lighthouse, indexation state, or traffic outcomes. No | ||
| claim below depends on knowing whether a page is actually *indexed* — only on | ||
| whether it is *indexable*. | ||
|
|
||
| --- | ||
|
|
||
| ## Root cause | ||
|
|
||
| Six dashboard generations were built. All six were rebuilt as a **new surface**; | ||
| none established a **contract** underneath. The concrete expression of that today: | ||
|
|
||
| > **`visibility` is decorative metadata. Nothing in any build step converts it | ||
| > into a robots directive, a sitemap entry, or a link-rendering decision.** | ||
|
|
||
| Every finding below is a symptom of that single missing invariant. | ||
|
|
||
| ### Evidence: `visibility` has no enforcement | ||
|
|
||
| 13 projects are marked `visibility: unlisted` in the public manifest. 12 have a | ||
| live URL. Their robots directives, fetched anonymously: | ||
|
|
||
| | Live `<meta name="robots">` | Count | Verdict | | ||
| |---|---:|---| | ||
| | `noindex,nofollow` | 1 | Matches declared intent | | ||
| | *(no robots meta at all)* | 10 | Declared unlisted, fully indexable | | ||
| | `index, follow` | 1 | **Explicitly contradicts** its own manifest entry | | ||
|
|
||
| One page carries an affirmative `index, follow` while its manifest row says | ||
| `unlisted`. That is not drift — it is two systems asserting opposite things with | ||
| no arbiter. | ||
|
|
||
| ### Evidence: the sitemap and the manifest are disjoint | ||
|
|
||
| | Measure | Value | | ||
| |---|---:| | ||
| | On-host project URLs in the manifest | 48 | | ||
| | Of those, returning HTTP 200 | **48 / 48** | | ||
| | Of those, present in `sitemap.xml` | **1** | | ||
| | Sitemap entries that are *not* a manifest project | **8 of 9** | | ||
|
|
||
| The sitemap is not stale — it is an **orphan from a different lineage**. Its 9 | ||
| entries are the root hub plus a brand palette, two internal strategy reports, and | ||
| four one-off pages. It has never described the project portfolio at all. | ||
|
|
||
| ### Evidence: hub links do not exist until JavaScript runs | ||
|
|
||
| The served hub HTML contains no project anchors. The project directory is built | ||
| client-side from the manifest, filtered on `visibility === 'public'`. The static | ||
| document offers one fallback: a link to the raw JSON. | ||
|
|
||
| This makes the manifest the **sole** discovery path — and it is the same file that | ||
| carries the unenforced `visibility` field. | ||
|
|
||
| --- | ||
|
|
||
| ## Findings | ||
|
|
||
| ### F-001 · Internal operations dashboard is publicly indexable | ||
| **Severity: Critical** · **Classification: remove from public** | ||
|
|
||
| `/command-center-061eed/` serves HTTP 200 with a complete internal operations | ||
| console: per-project status panels, an attention queue, git sync state, daily run | ||
| history, domain status, and a triage lane. | ||
|
|
||
| Verified state of the document `<head>`: | ||
|
|
||
| | Element | Present | | ||
| |---|---| | ||
| | `<meta name="robots">` | **No** — the string `noindex` appears **zero** times in the entire 229 KB document | | ||
| | `<link rel="canonical">` | No | | ||
| | `<meta name="description">` | No | | ||
| | `<h1>` | No | | ||
|
|
||
| `robots.txt` is `Allow: /` with no exclusions. The manifest entry sets | ||
| `visibility: public`, so the hub renders a card linking to it. | ||
|
|
||
| > [!WARNING] | ||
| > Internal design records state this surface was intended to be | ||
| > **"public (noindex)"**. The published artifact has no robots directive | ||
| > whatsoever. The intent was recorded and never implemented — and no check exists | ||
| > that would have caught the gap. | ||
|
|
||
| **Two properties make this worse than a normal exposure:** | ||
|
|
||
| 1. **It is republished by automation.** Internal run records show recurring | ||
| automated passes that regenerate and push this surface. A manual edit to the | ||
| published output **will be overwritten**. The fix must land in the generator. | ||
| 2. **`noindex` requires a crawl.** Blocking in `robots.txt` first would prevent | ||
| crawlers from ever *seeing* a `noindex`. Correct order: ship `noindex`, let it | ||
| be crawled, *then* consider disallowing. | ||
|
|
||
| Treat this as a disclosure cleanup that happens to have SEO side effects — not as | ||
| an SEO defect. | ||
|
|
||
| ### F-002 · Public manifest and private ops registry are the same document | ||
| **Severity: High** · **Classification: migrate — split the contract** | ||
|
|
||
| One `project-manifest.json` serves both portfolio discovery and internal | ||
| inventory. Consequences visible in the public file today: | ||
|
|
||
| - 79 entries, of which **18 are `visibility: private`** and 24 are `candidate`. | ||
| Private and candidate work is enumerated by name in a public JSON file. | ||
| - The schema carries `localPath` and `runCommand` fields. Both are **empty in all | ||
| 79 rows** — the leak has been cleaned, but the *channel* remains. Any future | ||
| writer that populates them publishes local filesystem paths. | ||
| - The rows most likely to be sensitive are exactly the rows least likely to get a | ||
| review pass, because they render nothing. | ||
|
|
||
| Empty-but-present private fields are a latent leak, not a resolved one. | ||
|
|
||
| ### F-003 · Sitemap describes an abandoned lineage | ||
| **Severity: High** · **Classification: preserve the file, regenerate the contents** | ||
|
|
||
| Quantified above: 1 of 48 live project URLs present; 8 of 9 sitemap entries are | ||
| not projects. Two of those 8 are internal strategy reports under | ||
| `/assets/reports/`, published and submitted for crawling. | ||
|
|
||
| The sitemap must become a **build artifact of the manifest**, never hand-authored. | ||
|
|
||
| ### F-004 · Project discovery requires JavaScript | ||
| **Severity: Medium** · **Classification: preserve the hub, fix the build** | ||
|
|
||
| No project anchors in the served HTML. Filtering, search, and presentation can | ||
| stay client-side; the `<a href>` set must be pre-rendered. | ||
|
|
||
| ### F-005 · Ops Hub v0.5 is the correct architecture and should not be rewritten | ||
| **Severity: High (opportunity)** · **Classification: migrate** | ||
|
|
||
| The Ops Hub generation lineage already established the right separation: | ||
|
|
||
| ``` | ||
| per-project state file → registry → generated hub → history + health panel | ||
| ``` | ||
|
|
||
| with candidate discovery, manual promotion, and a no-auto-registration default. | ||
| This is the only generation that treated the dashboard as a *rendered view* rather | ||
| than as the source of truth. v2 should be a **hardening** of it, not a rewrite. | ||
|
|
||
| Two known defects to carry forward as requirements: registry paths were fragile | ||
| across sync-backed directories, and **two parallel registry files existed in | ||
| different locations** — a split-brain the v2 schema must make structurally | ||
| impossible (one canonical registry, path resolved relative to the repo root). | ||
|
|
||
| ### F-006 · Governance already defines the missing truth model | ||
| **Severity: Medium (opportunity)** · **Classification: preserve** | ||
|
|
||
| The dashboard standards governance record already specifies canonical source | ||
| hierarchy, conflict badges, freshness SLAs, and the rule that raw capture never | ||
| owns verified truth. v2 should **import** these rules rather than reinvent them. | ||
|
|
||
| ### F-007 · One page's `noindex` may be correct, and nothing records that | ||
| **Severity: Medium** · **Classification: decision required** | ||
|
|
||
| `/act-two-catering/` carries `noindex,nofollow` and is marked `unlisted`. This is | ||
| the *only* unlisted page whose live directive matches its declared visibility. | ||
|
|
||
| It cannot be graded without knowing intent. If it is a live commercial page, this | ||
| is a serious defect. If it is a client preview, it is the one correctly configured | ||
| page on the property. **The audit's real finding is that intent is not recorded | ||
| anywhere** — so a correct configuration and a broken one are indistinguishable. | ||
|
|
||
| v2 requires an explicit `indexPolicy` with a reason string, so this question is | ||
| answered by the registry rather than by inference. | ||
|
|
||
| ### F-008 · Duplicate hub URL | ||
| **Severity: Low** · **Classification: unlink or canonicalize** | ||
|
|
||
| `/` and `/public-hub.html` both appear in the sitemap, share an identical | ||
| `<title>` (`Dave Robertson — Projects`), serve different bodies (91 KB vs 31 KB), | ||
| and **each self-canonicalizes to its own URL**. Two documents assert they are both | ||
| the canonical version of the same titled page. | ||
|
|
||
| Pick one canonical; redirect the other or point its canonical at the winner. | ||
|
|
||
| --- | ||
|
|
||
| ## Artifact classification | ||
|
|
||
| Grouped by disposition. Internal-only artifacts are described by role. | ||
|
|
||
| ### Preserve — active or canonical | ||
| | Artifact | Reason | | ||
| |---|---| | ||
| | Public portfolio hub (site root) | Correct product, defective build. Fix, don't replace. | | ||
| | `project-manifest.json` | Correct primitive. Split public/private concerns (F-002). | | ||
| | Dashboard standards governance record | Already defines v2's truth model (F-006). | | ||
| | Portfolio manifest reconciliation log | Most recent authority on manifest curation rules. | | ||
| | Standard audit procedure | Method reference for future passes. | | ||
| | Routing matrix for dev-hub surfaces | Routing rules migrate directly into v2. | | ||
|
|
||
| ### Migrate — source material for v2 | ||
| | Artifact | What survives | | ||
| |---|---| | ||
| | Ops Hub switchboard + v0.5 hardening + v0.1–v0.8 dev log | **The architecture itself** (F-005) — registry-driven generation, state reads, history, candidate discovery, health panel | | ||
| | Per-project `ops-state.json` pattern | The single strongest reusable primitive. Becomes schema v2. | | ||
| | Per-project ops-dashboard initializer | The per-project contract. Update for provenance + visibility. | | ||
| | `dashboard-registry.json` | Seeds the v2 registry. Must be de-duplicated to one canonical file. | | ||
| | Quick Start Command Center spec | **Provenance model only** — `{value, confidence, source, verifiedAt}` and freshness decay. Its published output is F-001. | | ||
| | Cross-Project Scan Dashboard | **Taxonomy only** — Security / Drift / Operability / Reuse. Becomes v2's audit lane. | | ||
| | Code Dashboard page template | **Layout only** — Top 3, Blocked, Registry, Open Threads. Not its stale content. | | ||
| | Operator Dashboard spec | **Five-zone layout and visibility gates only.** Its full integration surface is out of scope for v2 seed. | | ||
|
|
||
| ### Archive — freeze as historical, remove from active navigation | ||
| Code Dashboard page-breakdown template and its March snapshots; the earlier | ||
| unified dashboard sync mechanism; the generated cross-project scan HTML artifact; | ||
| the June daily command-center notes; the command-center UI/live-data context | ||
| update (*after* its publishing lessons are captured in F-001); the prior | ||
| context-bucket audit prompts. | ||
|
|
||
| These are useful provenance and misleading authority. Label them historical. | ||
|
|
||
| ### Unlink — remove from public navigation and sitemap, no deletion required | ||
| `/public-hub.html` · `/assets/reports/*` · `/assets/brand/brand-palette.html` | ||
| (unless deliberately public) · `/codedash-mar24/` · every `candidate` entry not | ||
| deliberately public. | ||
|
|
||
| Pending review before they stay linked: `/home-comic-dashboard/`, | ||
| `/daily-prophet/`, `/clever-paws/` — all three serve 200 with no robots meta. | ||
|
|
||
| ### Remove from public | ||
| `/command-center-061eed/` and its published mirror, plus any surface exposing | ||
| project queues, audit state, run identifiers, local paths, or client references. | ||
| **Fix the generator, not the output** (F-001). | ||
|
|
||
| --- | ||
|
|
||
| ## Severity roll-up | ||
|
|
||
| | Severity | Finding | | ||
| |---|---| | ||
| | 🔴 Critical | F-001 — internal ops console publicly indexable, actively republished | | ||
| | 🟠 High | F-002 public/private contract conflation · F-003 orphaned sitemap · F-005 architecture at risk of rewrite | | ||
| | 🟡 Medium | F-004 JS-only discovery · F-006 unimported governance · F-007 unrecorded index intent | | ||
| | ⚪ Low | F-008 duplicate hub URL | | ||
|
|
||
| --- | ||
|
|
||
| ## Remediation bundles | ||
|
|
||
| None of this has been executed. Approve per bundle. | ||
|
|
||
| <details> | ||
| <summary><strong>Bundle A — Safety.</strong> Closes the confirmed exposure.</summary> | ||
|
|
||
| 1. Add `noindex,nofollow` to the command center **in its generator**, so the next | ||
| automated republish preserves it rather than reverting it. | ||
| 2. Flip its manifest entry off `visibility: public` so the hub stops linking it. | ||
| 3. Decide whether it should remain on public hosting at all. | ||
| 4. Review `/home-comic-dashboard/`, `/daily-prophet/`, `/clever-paws/` for | ||
| content sensitivity before they stay publicly linked. | ||
| 5. Only after `noindex` has been crawled, consider a `robots.txt` disallow. | ||
|
|
||
| **Do not reorder step 5 ahead of step 1** — a disallow blocks the crawl that the | ||
| `noindex` depends on. | ||
| </details> | ||
|
|
||
| <details> | ||
| <summary><strong>Bundle B — Archive.</strong> Stops stale surfaces reading as current.</summary> | ||
|
|
||
| Mark the Code Dashboard lineage and the June command-center notes historical; | ||
| retain the cross-project scan as a dated snapshot; retain Ops Hub v0.5 as | ||
| migration source. | ||
| </details> | ||
|
|
||
| <details> | ||
| <summary><strong>Bundle C — Build v2.</strong> Per <a href="./OPS_HUB_V2_SPEC.md">the spec</a>.</summary> | ||
|
|
||
| Schemas, registry seed, validators, and a read-only private dashboard skeleton. | ||
| Depends on Bundle A only in sequencing — v2 should not be built on top of a live | ||
| exposure. | ||
| </details> | ||
|
|
||
| ## Recommended order | ||
|
|
||
| **Bundle A first.** It is the only confirmed high-severity exposure, it is being | ||
| actively re-published by automation, and it is cheap. Bundle C then inherits a | ||
| clean boundary instead of encoding the current one. | ||
|
|
||
| Tradeoff: the v2 build waits one pass. Worth it — v2's central invariant is the | ||
| public/private boundary, and building it while that boundary is knowingly broken | ||
| would bake the defect into the schema. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When Bundle A is applied,
noindexand removing the manifest link only reduce discovery; they do not prevent anyone who knows or guesses the URL from fetching the internal operations console. Because step 3 leaves continued public hosting as an optional decision, the bundle can be completed while the critical disclosure it claims to close remains accessible. Require removal from public hosting or authentication rather than treating that as a follow-up decision.Useful? React with 👍 / 👎.