Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
37df8ae
docs(plan): map dashboard refresh delivery
pacphi Sep 29, 2026
885056f
feat(dashboard): one server refresh operation behind POST /api/refresh
pacphi Sep 29, 2026
2e51400
docs(plan): complete dashboard refresh carry-ins
pacphi Sep 29, 2026
33a3d21
docs: repair dashboard usage citation
pacphi Sep 29, 2026
387bc0c
feat(dashboard): one Refresh control with the CLI three strengths; Re…
pacphi Sep 29, 2026
7bcc70a
fix(dashboard): show Unknown for unassessed Claude Code configuration
pacphi Sep 29, 2026
a567172
fix(dashboard): meet icon contrast in the host header
pacphi Sep 29, 2026
55ab5c8
fix(dashboard): honor changed Maintenance URL state
pacphi Sep 29, 2026
f1b9572
test(dashboard): prove refresh request and write boundaries
pacphi Sep 29, 2026
fc82c0b
docs(dashboard): record refresh client gate status
pacphi Sep 29, 2026
56bf59e
test(dashboard): restore Maintenance write safety journeys
pacphi Sep 29, 2026
a05f5c5
fix(dashboard): reread active System views on Reload
pacphi Sep 29, 2026
e8e4e20
fix(dashboard): retain write guard until refresh status reconciles
pacphi Sep 29, 2026
8420f9d
fix(dashboard): reconcile superseded refresh operations
pacphi Sep 29, 2026
bee3517
Merge branch 'develop' into feat/dashboard-refresh
pacphi Sep 29, 2026
9556196
fix(dashboard): start scans with POST requests
pacphi Sep 29, 2026
252bf4b
docs: align dashboard docs with the one Refresh control
pacphi Sep 29, 2026
19953b6
docs: correct refresh labels and machine stage order
pacphi Sep 29, 2026
97e8171
docs(adr): reconcile dashboard refresh supersessions
pacphi Sep 29, 2026
6036344
test(dashboard): cover ruflo component cwd forwarding
pacphi Sep 29, 2026
ede27d5
fix(live): resume displaced native transcript readers
pacphi Sep 29, 2026
e173bab
docs(live): state re-entry and structured-source limits
pacphi Sep 29, 2026
66982f2
docs(dashboard): reconcile final V3 evidence
pacphi Sep 29, 2026
0528a83
fix(activity): show paused scan record time
pacphi Sep 29, 2026
58e51b6
Merge branch 'develop' into feat/dashboard-refresh
pacphi Sep 29, 2026
d2c1833
fix(activity): reject impossible scan dates
pacphi Sep 29, 2026
4c45148
docs(archive): record dashboard refresh implementation
pacphi Sep 29, 2026
6597a62
fix(dashboard): honor current project-tree refresh selection
pacphi Sep 29, 2026
cd5cd08
test(maintenance): align evidence method with Refresh vocabulary
pacphi Sep 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# V3 Activity paused-time consumer report

## Source and contract

- Base: `66982f22` in `feat/dashboard-refresh`.
- Read the V4 B8 producer in `agentic-kit-v4-rest` without changing it. A paused history row has `recordedAt` and `completedAt: null`; completed rows retain `completedAt`.

## Change

- Activity projection keeps a bounded, valid ISO `recordedAt` separately from `completedAt`, uses it to choose the latest state per source and environment, and falls back to a valid completion time. Invalid scan timestamps become `null`; unrelated metadata is not projected.
- The v2 Activity API allowlists a bounded ISO pause timestamp and omits invalid stamps and private metadata.
- The Activity history table sorts, groups, and displays by the valid recorded time or completion time. Its labels and empty copy describe scan records without claiming every scan completed.

## Evidence

- Red phase: guarded focused suites had 3 expected failures for missing pause time and stale latest-state selection.
- Green phase: `env -u FORCE_COLOR node scripts/run-tests.mjs exec -- --test tests/kit/maintenance-management-activity.test.mjs tests/kit/maintenance-dashboard-v2-api.test.mjs`: 58 passed, 0 failed.
- Guarded actual dashboard browser run, `env -u FORCE_COLOR node scripts/run-tests.mjs exec -- tests/ui/dashboard-ui.mjs`: 514 passed, 0 failed. The new assertion inspects actual rendered table rows for a newer paused record and older completed records.
- `./node_modules/.bin/tsc -p tsconfig.json --noEmit`: passed.
- Focused ESLint: 0 errors, one pre-existing `max-lines` warning in `maintenance-api.mjs` (file has 1021 lines, threshold 1000).
- `git diff --check`: passed.

## Limits

- V4 B8 producer remains on its separate branch. This change is the consumer contract only, pending integration and independent review.
- Full unit and UI suites were not repeated after the final timestamp-validation refinement; focused unit tests, lint, and typecheck passed after it. The guarded browser run covered the Activity renderer before that refinement.

## Scoped review fix: impossible calendar dates

- Review found that the prior ISO shape plus `Date.parse` accepted `2026-09-31T12:00:00Z`, letting a paused row outrank a real September 30 completion and render on October 1.
- The Activity projection now checks the calendar day against its month and leap year, plus clock component bounds, before accepting a scan timestamp. The v2 Activity API uses the same validator for `recordedAt`.
- New cases reject September 31 and a non-leap February 29 at both projection boundaries, retain a valid completion timestamp when the recorded time is rejected, and retain a valid leap day with an offset and fractional seconds.
- Guarded focused tests: `env -u FORCE_COLOR node scripts/run-tests.mjs exec -- --test tests/kit/maintenance-management-activity.test.mjs tests/kit/maintenance-dashboard-v2-api.test.mjs` passed 61 tests after the validator change. The final fallback assertions were added afterward and rerun before this fix commit.
- `./node_modules/.bin/tsc -p tsconfig.json --noEmit` passed. Focused ESLint had 0 errors and the existing file-length warning in `maintenance-api.mjs`.
- Browser and full suites were not repeated for this scoped validation fix; the prior guarded browser run remains the renderer evidence, with full gates assigned to integration.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ and current platform limits.
| **setup** | Installs/updates ruflo + agentic-qe globally (handling npm ≥11.17's `allow-scripts` so natives build; AgentDB ships inside ruflo, so ak installs no separate copy), installs and verifies the exact Ruflo-compatible **agent-browser** native executor without adding its plugin/skills (`--no-agent-browser` disables it), installs the **RuvNet Brain** (an offline knowledge base over the rUv stack, powering the `search_ruvnet` MCP — a ~2 GB one-time download, prompted; skip with `--no-ruvnet-brain`), deploys the token-audit skill, merges the managed guidance blocks into the machine-wide guidance files (`~/.claude/CLAUDE.md`, plus `~/.codex/AGENTS.md` on codex machines), offers one-time MCP registration (user scope, with a tool-family picker), and — inside a repo — initializes the project: sanitized `ruflo init`, absolute memory-path pin, a **verified** store→disk write, statusline footer, and a background daemon with **local-only ($0) workers** (token-spending AI workers stay opt-in behind upstream's machine-wide budget). Project scope triggers on a `.git` entry in the current folder; without one it's skipped with a note. `--project` forces the same project setup in the current directory (e.g. a not-yet-`git init`-ed folder); it does not locate an ancestor repository. Project initialization runs `ruflo init --full --force` and can replace existing agent configuration, so read the [setup scope and project mutation contract](docs/setup.md) before using it on an existing project. `--minimal` skips it, `--yes` accepts all prompts (non-interactive), `--no-aqe` / `--no-agent-browser` / `--no-ruvnet-brain` / `--no-security` disable those subsystems, and `--reconfigure` re-offers MCP registration. `--codex` enables + installs the Codex host during setup (ambidextrous dual-host mode; both hosts become available for routing), and `--primary-host claude\|codex` picks which host leads (codex implies `--codex`). |
| **status** | Per-subsystem ✓/⚠/✗ (versions, the kit's own version, **ruvnet-brain**, natives, **memory-pin**, security, learning, aqe/RVF, the managed **agent-browser** package/native/config/browser readiness, MCP, **hosts**, **providers**, **routing**, daemons, guidance blocks, statusline), each drift row naming what `sync` would do about it, or marking a step you must take yourself as `→ manual:` (sync never plans those) — plus a **health-history** line that flags regressions since the last sync. Browser status is filesystem-only: it never runs doctor or launches Chrome. |
| **sync** | The one convergence verb: upgrades first when a new release exists, then re-heals everything an upgrade wipes, then re-checks and reports. Included in that heal: it **installs any enabled frontier host** (claude/codex/opencode) that's entirely absent — never touching an external (mise/brew/native) install — and **re-applies provider wiring** (the `ENABLE_*` host env, OpenCode's native configuration, the AQE default/fallback/agent overrides, admitted Agentic-QE 3.13.12+ `externalProviders`, and ruflo API providers) whenever it has drifted. External-provider reconciliation preserves foreign entries, refuses same-id conflicts, and prunes only entries whose exact value still matches an agentic-kit ownership receipt. On a dual-host project, sync also **seeds/heals the Claude/Codex default routing policy**. It appends a health-history snapshot, refreshes RuvNet Brain when enabled, and self-updates the kit last. A planned fix whose status row is still there afterwards is reported `unresolved:` and sync exits 1. A row whose fix you do by hand (`→ manual:`) never changes sync's exit code; a failing or warning one is listed under "needs your action". `--no-upgrade` skips self-update and package upgrades. `--skip <subsystem>` (repeatable) leaves one subsystem out of this run only, including the step it owns; it is reported "skipped by request" and never counts as a failure. `--json` prints one JSON result on stdout (`plan`, `steps`, `unresolved`, `skipped`, `needsYourAction`, `converged`, `exitCode`) and sends the human lines to stderr. Model refresh/diff/plan findings remain advisory. |
| **dashboard** | Opens the local web dashboard (`127.0.0.1:7431`, localhost-only, never detaches) with five primary areas: **About · Overview · Usage · Observability · System**. Ordinary views remain observation-only. System's **Full scan** remeasures local inventory and then chains one provider check. **System → Maintenance** is the sole action surface, with four destinations: **Inventory** (scope → repository where applicable → type → resource → exact installation), **Guidance** (only outcomes the kit can ground), **Discovery** (where it looks), and **Activity** (receipts, undo, interruption audits). Every write is one exact placement and one action, with a server-derived short-lived plan, explicit confirmation, and a one-use capability. Advisory remains a measurement; the former Catalog tab redirects to Inventory and its cards now sit in System Summary. The page is self-contained, offline-first, protected by a per-session token, and never executes a browser-supplied command. Action targets resolve server-side; Discovery accepts validated source-root configuration. Full navigation and security semantics: [Dashboard guide](docs/dashboard.md); provider and recovery limits: [Maintenance runbook](docs/maintenance.md). **Auto-opens your browser** (`--no-open` for headless/SSH); `--port N` changes the port. Stop with Ctrl-C. (Also available as `ak x dashboard`.) |
| **dashboard** | Opens the local web dashboard (`127.0.0.1:7431`, localhost-only, never detaches) with five primary areas: **About · Overview · Usage · Observability · System**. Ordinary views remain observation-only. Choose **Refresh machine** in the header and press **Refresh** to remeasure the machine, refresh Maintenance evidence, and rebuild the inventory. **System → Maintenance** is the sole action surface, with four destinations: **Inventory** (scope → repository where applicable → type → resource → exact installation), **Guidance** (only outcomes the kit can ground), **Discovery** (where it looks), and **Activity** (receipts, undo, interruption audits). Every write is one exact placement and one action, with a server-derived short-lived plan, explicit confirmation, and a one-use capability. Advisory remains a measurement; the former Catalog tab redirects to Inventory and its cards now sit in System Summary. The page is self-contained, offline-first, protected by a per-session token, and never executes a browser-supplied command. Action targets resolve server-side; Discovery accepts validated source-root configuration. Full navigation and security semantics: [Dashboard guide](docs/dashboard.md); provider and recovery limits: [Maintenance runbook](docs/maintenance.md). **Auto-opens your browser** (`--no-open` for headless/SSH); `--port N` changes the port. Stop with Ctrl-C. (Also available as `ak x dashboard`.) |
| **usage** | `score` and `prompts` summarize retained local transcript evidence. `status` reads provider-account analytics from cache; `refresh openrouter` explicitly contacts the OpenRouter management API using `OPENROUTER_MANAGEMENT_KEY`, then writes a credential-free mode-`0600` cache. Cache reads make no OpenRouter request. Account rows have no grounded host/session/project correlation and are never merged into transcript totals. |
| **models** | Builds a private, host-scoped model inventory from Claude, Codex, OpenCode, Ollama, bounded local usage evidence, and a dated bundled record of Anthropic's public model/lifecycle facts. `status`, `diff`, `explain`, and `plan` are cache-only and read-only; `refresh --online` is the sole online-catalogue boundary. Public facts never imply account or OpenRouter routability. Swap plans enumerate routes plus Agentic QE/Ruflo consumers and print a copyable canonical action without executing it. The CLI exposes exact local evidence deliberately; the Dashboard exposes source-proven public catalogue identity and uses the owner-visible model read contract; secret-shaped values remain masked. See [Model lifecycle intelligence](docs/models.md). |
| **admin** | Opens the **maintainer admin** (`127.0.0.1:7432`, localhost-only, foreground) — the project-telemetry sibling of `dashboard`, with the same dark/light visual theme and persisted theme preference: unique repo visitors and cloners (GitHub traffic API, needs a push-access token via `GITHUB_TOKEN`/`GH_TOKEN`/`gh auth token` — panels degrade honestly without one), contributors and watchers, npm download momentum (last 7d vs prior 7d, sparklines — shown as trend only, never an absolute reach number, since mirrors/CI inflate the raw count), latest CI run status and open Dependabot alerts, a **"since you last looked"** delta strip over a local baseline, open issues/PRs from others (oldest first), and external humans ranked by recency (bots excluded). Access is gated by a **per-session token** carried in the URL fragment and sent header-only; the page makes **zero external fetches** (the server proxies GitHub/npm; your credential never reaches the page or the payload). Where `dashboard` is offline-first, `admin` does deliberate GitHub/npm egress — that contract split is why they're siblings, not tabs. `--port N`, `--no-open`; Ctrl-C stops. (Also available as `ak x admin`.) |
Expand Down
12 changes: 12 additions & 0 deletions docs/adr/0012-observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -670,3 +670,15 @@ turns the dashboard into a fleet service nor makes telemetry collection continuo
- **Exact-folder leases (#238 item 2).** A runtime lease no longer requires a Git repository when
an exact-folder match joins the process to its transcript; see the 2026-08-03 runtime identity
amendment above.

### 2026-09-29 follow-up: bounded re-entry and structured-source evidence

An idle stop retains active tailer offsets. A native transcript displaced from the newest-file
window also retains its reader state in memory, up to twice the configured file bound (at least
two dormant readers). Re-entry within that bound resumes without replaying accepted records.
After dormant eviction, re-entry reads from the start; a new dashboard process has no persisted
native offset and bootstraps existing-file metadata before following new appends. This does not
create durable exactly-once delivery.

The optional Ruflo and agentic-qe structured live-events input is experimental. Parser fixtures
exist, but no real producer has been verified. An explicit source path does not prove activity.
21 changes: 13 additions & 8 deletions docs/adr/0025-machine-footprint-metrics.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# ADR-0025 — Machine footprint: infrastructure metrics for install, runtime, storage, and catalog

- **Status:** Implemented
- **Updated:** 2026-09-28 — CLI parity (§5) is now `ak system [--refresh[=live|machine]]
- **Updated:** 2026-09-29 — §5 deep measurement now starts with `POST /api/refresh` at
`machine` strength; GET routes are passive. The old GET-started scan rationale is withdrawn
because a read request must not start measurement work. See
[ADR-0063](0063-evidence-store-and-refresh-vocabulary.md).
- **Earlier update:** 2026-09-28 — CLI parity (§5) is now `ak system [--refresh[=live|machine]]
[--project-trees] [--json]` (`src/lib/refresh.mjs`'s shared strengths, replacing the retired
`--deep`); §5's `GET /api/system?refresh=deep` rationale is untouched by this branch and belongs
to a later remediation program's dashboard work (remediation program, branch 6b; see
Expand Down Expand Up @@ -322,14 +326,14 @@ silent "Other" slice into a to-do list a release can close.
([ADR-0014](0014-dashboard-auth-and-remediation.md)), and zero egress
([ADR-0007](0007-maintainer-admin-local-telemetry.md)'s offline side of the line) as every
other dashboard route.
- `GET /api/system?refresh=deep` — starts or attaches to the single-flight deep scan. The
dashboard server is deliberately GET-only; a refresh is a re-*measurement* of local state, not
a mutation of user data, so it stays within that contract. `&trees=1|0` sets whether that scan
walks project working trees; it is a **measurement** parameter, not a view filter, because
trees that were never walked cannot be un-hidden client-side.
- `POST /api/refresh` with `{"strength":"machine","projectTrees":true}` starts
the staged single-flight refresh; `projectTrees` is an optional boolean measurement choice.
The earlier `GET /api/system?refresh=deep&trees=1|0` trigger and its GET-only rationale
are withdrawn: a GET must never start scan work, even when the work only measures local
state. Trees that were never walked cannot be un-hidden client-side.
- `ak system [--refresh[=live|machine]] [--project-trees] [--json]` — CLI parity sharing the same
collector, following the usage-scorecard precedent of one collector behind both surfaces
(`--refresh=machine` is the CLI equivalent of the `?refresh=deep` route below).
(`--refresh=machine` selects the same strength as the dashboard POST).
- `GET /api/system/summary` (amendment, 2026-09-26; extended 2026-09-28) — the page's read: the
same payload and parameters with `catalog`, `storage`, `install`, `projects` and `consumers` each
projected to an allow-list of keys and items cut to what the page draws (including
Expand Down Expand Up @@ -568,7 +572,8 @@ The draft left four points open. All four are decided; this section is the recor
large corpus — the surprise cost is worse than a stale figure that says how stale it is. The
snapshot's `asOf` is always rendered, and beyond `SNAPSHOT_STALE_AFTER_MS` (7 days) the
freshness label turns amber and reads "stale, rescan". Opening the System tab issues a plain
`GET /api/system/summary`; only the Rescan control adds `?refresh=deep`.
`GET /api/system/summary`; only explicit Refresh machine starts a measurement with
`POST /api/refresh`.
4. **Windows ships a current-user census plus a best-effort true `cwd`, degrading honestly, with no
dependency added.** The draft's "unsupported on win32" answer would have blanked the whole
Runtime view on a supported platform. Instead `src/lib/live/win-process-survey.ps1` — a plain text
Expand Down
10 changes: 6 additions & 4 deletions docs/adr/0044-receipt-aware-maintenance-control-plane.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

- **Status:** Implemented
- **Date:** 2026-09-03
- **Updated:** 2026-09-28 — the CLI verb for the explicit scan this ADR's v1 `ak maintain scan`
- **Updated:** 2026-09-29 — the dashboard explicit scan starts with `POST /api/refresh`;
the retired `GET /api/maintenance?refresh=scan` is rejected. See ADR-0063.
- **Earlier update:** 2026-09-28 — the CLI verb for the explicit scan this ADR's v1 `ak maintain scan`
contract describes is now `ak maintain --refresh[=machine]` (the exact `?refresh=scan` dashboard
route below is unaffected — that half of the vocabulary belongs to a later remediation program's
dashboard work; see [ADR-0063](0063-evidence-store-and-refresh-vocabulary.md))
Expand Down Expand Up @@ -232,9 +234,9 @@ a body no larger than 64 KiB. The SSE query-token exception does not apply. The
read-only interruption audit and separately confirmed single-receipt reconciliation.

Plain <code>GET /api/maintenance</code> reads the latest persisted scan report and never polls a
provider. The exact <code>?refresh=scan</code> query performs and atomically persists a provider scan;
other or duplicate query parameters are rejected. The global browser poll remains passive. A
successful persisted System deep rescan chains exactly one Maintenance scan. See ADR-0045.
provider. An explicit `POST /api/refresh` runs the provider scan as its Maintenance stage and persists
the report; `GET /api/maintenance?refresh=scan` is rejected. The global browser poll remains
passive. A successful machine measurement precedes one Maintenance scan. See ADR-0045.

The view groups **Updates ready**, **Safe cleanup**, **Needs review**, **Unsupported or blocked**,
and **Recent changes / Undo**. Every row exposes a direct imperative; the selected finding adds its
Expand Down
Loading
Loading