Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Binary file added assets/cockpit/agentflow-icon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cockpit/agentflow-logo-transparent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cockpit/agentflow-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 32 additions & 5 deletions docs/cockpit-qa.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,26 @@ Docker deployment is intentionally a second pass. This checklist covers local an
AGENTFLOW_REPOSITORIES=smota/agentflow-sdlc GITHUB_TOKEN=<read-token> pnpm cockpit
```
2. Open `/` and verify Goal Board loads.
- View tabs include Goals, Releases, Reviews, and Follow-ups.
- Release dashboard is first-class, above the goal workspace.
- Release metrics include awaiting release, missing release notes, and release blockers.
3. Open `/issues/119` and verify:
- SDLC timeline renders.
- Evidence Health renders.
- Relationship Graph renders nodes/edges.
- Comment lanes render workflow sections.
- Goal detail has a back link to Goal Command Center.
- Compact goal header uses stable grammar: identity, status/path/release badges, then actions.
- Source is an external header action, not mixed into conceptual badges.
- Selected Path and Version / Release Lens appear in the summary strip.
- Human review status is explicit when required by high-assurance path.
- Next-best-actions render as compact row cards.
- Role Flow Contributions render icon/status first instead of generic timeline framing.
- Readiness Health renders icon/color state markers, score, denominator, excluded skipped/not-applicable checks, and hover/focus detail.
- Relationship Map renders only when relationships exist and explains its navigation purpose.
- Activity & Decisions hides empty lanes or shows a compact empty state.
- Guarded actions panel says server-side auth/CSRF/audit required.
4. Open `/issues/127/replay` and verify compact Goal Story replay.
4. Open `/issues/127/replay` and verify Goal Story replay.
- Navigation links back to Goal detail and Goal Command Center.
- Timeline clearly says `Oldest → newest`.
- Events render on a vertical flow line ending at Current state.
- Page copy says how the goal moved from intent to current state.
5. Open `/issues/127/replay.md` and verify markdown export.
6. Confirm replay page says read-only reconstruction and has no rerun/execute control.
7. Confirm no raw transcript, prompt, tool input, secret, or full log content appears.
Expand Down Expand Up @@ -81,6 +94,20 @@ Use a process manager such as systemd, pm2, or a platform process runner. Termin
- Disable telemetry with `COCKPIT_RUNNER_TELEMETRY=false`.
- Remove OAuth app credentials if compromised.

## Goal Command Center UX checklist

- [ ] Header uses repo-local AgentFlow logo and product palette.
- [ ] Home page answers what goal needs attention and why within one screen.
- [ ] Top metrics, highlight zone, and next-best-actions are visible above the goal list.
- [ ] GitHub issue/PR/comment language is secondary to goal, confidence, evidence, next action, and follow-ups.
- [ ] Fail-safe states avoid generic `unknown` warnings except real errors.
- [ ] Header hides local token implementation detail and labels the repository as Workspace.
- [ ] Goal Story appears as a styled action, not an unstyled utility link.
- [ ] Readiness Health behaves like a health check with score, dimensions, denominator, and floating details.
- [ ] Skipped-by-path roles explain why they were skipped and do not reduce score.
- [ ] Release dashboard is a first-class view with release candidate, target branch, awaiting-release goals, missing notes, and blockers.
- [ ] Version / Release Lens distinguishes merged, awaiting release, delivered/closed, and no-release-impact states.

## Release checklist

- [ ] `pnpm test` passed.
Expand Down
36 changes: 20 additions & 16 deletions docs/cockpit.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AgentFlow Cockpit

AgentFlow Cockpit is the planned optional UI for goal-oriented SDLC delivery. It presents GitHub issues, epics, comments, PRs, role-pass evidence, validation, and follow-ups as AgentFlow workflow state instead of a generic issue list.
AgentFlow Cockpit is the optional Goal Command Center for goal-oriented SDLC delivery. It turns GitHub issues, epics, comments, PRs, role-pass evidence, validation, and follow-ups into goals, evidence health, role flow contributions, graph navigation, next-best-actions, and replayable goal stories.

Cockpit is optional. The CLI/GitHub workflow remains authoritative and fully usable without Cockpit.

Expand Down Expand Up @@ -45,17 +45,17 @@ Cockpit does not require a mounted repo checkout in remote mode. Future Docker d

## Opinionated views

### Goal Board
### Goal Command Center

Shows goals grouped by workflow state: Intake, Scoped, Planned, Implementation, Validation, Review, PR Ready, Done, and Blocked.
Shows top metrics, a highlight goal, next-best-actions, goal health, follow-ups, and human gates. GitHub issue details are secondary metadata; the primary language is goal, confidence, evidence, next action, and role flow.

### Epic View

Rolls up child issues, dependencies, acceptance matrix, risk, active workstreams, PRs, follow-ups, and decisions.

### Issue SDLC View
### Goal Detail, Selected Path, and Role Flow Contributions

Shows phases 0-8:
Shows the selected path/profile/risk first, then phases 0-8 as role contributions rather than a generic timeline. Roles can be complete, skipped by path, not applicable, not started, needs attention, blocked, or error:

1. Product manager / JTBD
2. Analyst
Expand All @@ -67,20 +67,24 @@ Shows phases 0-8:
8. Tech writer
9. PR readiness

Each phase shows role-pass completeness, evidence, validation, handover, and next role contract.
Each role card shows completion first. Supporting evidence is detail/proof behind the role status. Roles skipped by selected path explain why and do not reduce readiness.

### Evidence Health
### Readiness Health

Reports governance completeness, not model confidence:
Reports governance completeness as a path-aware score with explainable dimensions, not model confidence. The denominator includes only applicable checks; skipped-by-path and not-applicable checks are excluded:

- Required policy read state.
- Acceptance criteria.
- Role-pass fields.
- Validation status.
- Review independence.
- Human gate requirements.
- PR manifest readiness.
- Follow-up disposition.
- Scope.
- Design.
- Implementation.
- Validation.
- Review/gates.
- Follow-ups.

Missing optional evidence is shown with fail-safe copy instead of generic `unknown` warnings.

### Version / Release Lens

Shows whether the goal is in progress, merged, awaiting release, or delivered/closed. It also surfaces target branch, release impact, candidate version when known, and release-note state. This reinforces that merged work is not always delivered work.

### Comments lanes

Expand Down
121 changes: 121 additions & 0 deletions lib/__tests__/cockpit-goal-model.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { describe, expect, it } from 'vitest'
import {
buildAgentFlowGoalModel,
buildCommandCenterModel,
buildReleaseDashboard,
deriveHumanGate,
deriveSelectedPath,
deriveVersionLens,
DISPLAY_STATES,
} from '../cockpit-goal-model.mjs'

describe('AgentFlow goal model', () => {
it('derives health score and next-best-actions from GitHub evidence', () => {
const goal = buildAgentFlowGoalModel({
issue: issue({ body: '## Acceptance criteria\n- [ ] works\n\n## Test plan\n- pnpm test' }),
comments: [{ body: '<!-- agentflow:validation-summary -->\npnpm test passed' }],
pullRequests: [{ number: 1, title: 'PR', merged_at: null }],
})
expect(goal.evidenceHealth.score).toBeGreaterThan(60)
expect(goal.nextBestActions.map((action) => action.id)).toContain('request-review')
expect(goal.roleContributions.find((item) => item.phase === 'analyst').state).toBe(
DISPLAY_STATES.recorded,
)
})

it('prioritizes human gate for sensitive goals', () => {
const goal = buildAgentFlowGoalModel({
issue: issue({
body: '## Acceptance criteria\n- [ ] works\n\nRemote auth security high-assurance',
}),
})
expect(goal.nextBestActions[0].id).toBe('request-human-gate')
expect(goal.status).toBe('blocked')
})

it('builds command center metrics and highlight', () => {
const model = buildCommandCenterModel({
issues: [issue({ number: 1, title: 'A' }), issue({ number: 2, title: 'B', body: '' })],
})
expect(model.metrics.activeGoals).toBe(2)
expect(model.topActions.length).toBeGreaterThan(0)
expect(model.highlight).toBeTruthy()
})

it('excludes skipped-by-path roles from readiness denominator', () => {
const goal = buildAgentFlowGoalModel({
issue: issue({
body: '## Acceptance criteria\n- [ ] typo fixed\n\n## Test plan\n- docs reviewed\n\ndocs-only bounded low-risk',
}),
comments: [{ body: 'validation passed. review complete.' }],
pullRequests: [{ number: 2, title: 'Docs PR', base: { ref: 'development' } }],
})
expect(goal.selectedPath.profile).toBe('bounded')
expect(goal.roleContributions.find((item) => item.phase === 'architect')).toMatchObject({
status: 'skipped-by-path',
scoreImpact: 'excluded',
})
expect(goal.evidenceHealth.excluded).not.toContain('roleFlow')
expect(goal.evidenceHealth.dimensions.find((item) => item.id === 'roleFlow').detail).toContain(
'applicable roles',
)
})

it('builds first-class release dashboard rollup', () => {
const model = buildCommandCenterModel({
issues: [issue({ number: 1, title: 'Ship A', labels: [{ name: 'feature' }] })],
pullRequestsByIssue: {
1: [{ number: 3, merged_at: '2026-01-01T00:00:00Z', base: { ref: 'development' } }],
},
})
expect(model.releaseDashboard).toMatchObject({ targetBranch: 'development' })
expect(model.releaseDashboard.awaitingRelease).toHaveLength(1)
expect(model.metrics.missingReleaseNotes).toBe(1)
expect(buildReleaseDashboard(model.goals).includedGoals).toHaveLength(1)
})

it('derives version lens for merged development work awaiting release', () => {
const version = deriveVersionLens({
issue: issue({ labels: [{ name: 'feature' }] }),
pullRequests: [
{ number: 3, merged_at: '2026-01-01T00:00:00Z', base: { ref: 'development' } },
],
})
expect(version.state).toBe('awaiting-release')
expect(version.releaseImpact).toBe('minor')
expect(version.releaseNoteState).toBe('needs-decision')
})

it('infers high-assurance selected path from sensitive work', () => {
expect(
deriveSelectedPath({
issue: issue({ body: '## Acceptance criteria\n- [ ] secure\n\nRemote auth security' }),
}),
).toMatchObject({ profile: 'high-assurance', risk: 'high' })
})

it('tracks required human gate status explicitly', () => {
const selectedPath = deriveSelectedPath({
issue: issue({ body: '## Acceptance criteria\n- [ ] secure\n\nRemote auth security' }),
})
expect(deriveHumanGate({ selectedPath, comments: [] })).toMatchObject({
required: true,
status: 'not-requested',
})
expect(
deriveHumanGate({
selectedPath,
comments: [{ body: 'human security review approved and complete' }],
}),
).toMatchObject({ status: 'complete' })
})
})

function issue({
number = 1,
title = 'Goal',
body = '## Acceptance criteria\n- [ ] works',
labels = [{ name: 'drafted-by:pi' }],
} = {}) {
return { number, title, body, labels, state: 'open' }
}
11 changes: 7 additions & 4 deletions lib/__tests__/cockpit-read-model.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@ describe('cockpit read model', () => {
expect(view.classification.isAgentFlowManaged).toBe(true)
expect(view.commentLanes.Handover).toHaveLength(1)
expect(view.evidenceHealth.status).toBe('complete')
expect(view.goal.title).toBe('Read-only MVP')
expect(view.goal.nextBestActions.length).toBeGreaterThan(0)
})

it('builds goal board columns with blocked evidence surfaced', () => {
it('builds command center metrics with attention surfaced', () => {
const board = buildGoalBoard({
issues: [
managedIssue({ number: 1, title: 'Good' }),
{ number: 2, title: 'Missing', labels: [], body: '' },
],
})
expect(board.Scoped).toHaveLength(1)
expect(board.Blocked).toHaveLength(1)
expect(board.metrics.activeGoals).toBe(2)
expect(board.goals).toHaveLength(2)
expect(board.topActions.length).toBeGreaterThan(0)
})

it('rolls up epic child evidence', () => {
Expand All @@ -37,7 +40,7 @@ describe('cockpit read model', () => {
],
})
expect(rollup.totals.children).toBe(2)
expect(rollup.totals.blocked).toBe(1)
expect(rollup.totals.blocked).toBe(2)
expect(rollup.totals.evidenceComplete).toBe(1)
})
})
Expand Down
Loading
Loading