diff --git a/docs/ECC-2.0-GA-ROADMAP.md b/docs/ECC-2.0-GA-ROADMAP.md index 4a3ccf5b..b789d622 100644 --- a/docs/ECC-2.0-GA-ROADMAP.md +++ b/docs/ECC-2.0-GA-ROADMAP.md @@ -30,7 +30,7 @@ As of 2026-05-12: Linear project status updates remain the active tracking surfaces until the workspace is upgraded or issue capacity is freed. - `npm run harness:audit -- --format json` reports 70/70 on current `main`. -- `npm run observability:ready` reports 14/14 readiness on current `main`. +- `npm run observability:ready` reports 16/16 readiness on current `main`. - `docs/architecture/harness-adapter-compliance.md` maps Claude Code, Codex, OpenCode, Cursor, Gemini, Zed-adjacent, dmux, Orca, Superset, Ghast, and terminal-only support to install paths, verification commands, and risk @@ -153,7 +153,7 @@ As of 2026-05-12: - Keep public PRs and issues below 20, with zero as the preferred release-lane target. -- Maintain 70/70 harness audit and 14/14 observability readiness after every +- Maintain 70/70 harness audit and 16/16 observability readiness after every GA-readiness batch. - Do not publish release or social announcements until the GitHub release, npm/package state, billing state, and plugin submission surfaces are verified @@ -187,7 +187,7 @@ is not complete unless the evidence column exists and has been freshly verified. | Linear roadmap is detailed | Linear project status plus repo mirror | Repo mirror exists; issue creation was retried on 2026-05-12 and remains blocked by the workspace free issue limit | Needs recurring status updates after each merge batch | | Flow separation and progress tracking | Flow lanes with owner artifacts and update cadence | This roadmap defines lanes below | Active | | Realtime Linear sync | Project updates while issue limit is blocked; issues later | ECC-Tools #39 implements opt-in Linear API sync for deferred follow-up backlog items | Needs workspace capacity/config rollout | -| Observability for self-use | Local readiness gate, traces, status snapshots, risk ledger | `npm run observability:ready` reports 14/14 | Complete for local gate | +| Observability for self-use | Local readiness gate, traces, status snapshots, HUD/status contract, risk ledger | `npm run observability:ready` reports 16/16 | Complete for local gate | | Proper release and notifications | Release tag, npm publish state, plugin state, social posts | Publication readiness gate exists | Not complete | ## Execution Lanes And Tracking Contract @@ -275,7 +275,7 @@ Target: 2026-06-07 Acceptance: -- Observability readiness remains 14/14 and is backed by JSONL traces, status +- Observability readiness remains 16/16 and is backed by JSONL traces, status snapshots, risk ledger, and exportable handoff contracts. - HUD/status model covers context, tool calls, active agents, todos, checks, cost, risk, and queue state. diff --git a/docs/architecture/hud-status-session-control.md b/docs/architecture/hud-status-session-control.md new file mode 100644 index 00000000..8b773e20 --- /dev/null +++ b/docs/architecture/hud-status-session-control.md @@ -0,0 +1,80 @@ +# HUD Status And Session Control Contract + +This contract defines the portable status payload ECC uses for local operator +surfaces, handoffs, and future HUDs. It is intentionally harness-neutral: a +Claude Code statusline, Codex pane, dmux session, OpenCode run, or terminal-only +workflow can emit partial data without changing field names. + +The canonical example lives at +[`examples/hud-status-contract.json`](../../examples/hud-status-contract.json). + +## Payload Shape + +Every status payload uses `schema_version: "ecc.hud-status.v1"` and keeps these +top-level sections stable: + +| Field | Purpose | Primary Source | +|---|---|---| +| `context` | Model, harness, repo, branch, worktree, session id, and context-window pressure | statusline stdin, git, session adapters | +| `toolCalls` | Recent tool counts, pending calls, stale calls, and last tool event | `loop-status`, `tool-usage.jsonl`, hook bridge | +| `activeAgents` | Current workers/subagents, runtime state, branch, worktree, objective, and handoff paths | dmux/orchestration snapshots | +| `todos` | Current in-progress task and todo counts | Claude todos, local task files, plan metadata | +| `checks` | Local and remote validation status with command/check URLs when available | CI, local commands, release gates | +| `cost` | Session spend, token counts, budget, and trend | cost tracker, metrics bridge | +| `risk` | Attention state, conflict pressure, stale calls, dirty worktree, and manual-review flags | readiness gates, git, queue state | +| `queueState` | GitHub PR/issue/discussion counts, conflict queue, merge queue, and stale-salvage queue | GitHub sync, work items | +| `sessionControls` | Supported operator actions for the current target | ECC CLI, dmux, git/GitHub | +| `sync` | Linear, GitHub, and handoff publication state | status updates, work items, handoff writer | + +Fields can be `null`, empty arrays, or `"unknown"` when a harness cannot expose +the signal. Producers should not invent incompatible names. Consumers should +render missing sections as unavailable, not as green. + +## Session Controls + +The minimum session-control vocabulary is: + +| Control | Meaning | +|---|---| +| `create` | Start a new isolated run, worktree, or orchestration plan | +| `resume` | Reattach to an existing session or historical target | +| `status` | Emit the current payload without mutating state | +| `stop` | Request a graceful stop or mark the session completed | +| `diff` | Show current working-tree or worker diff | +| `pr` | Open or inspect the linked pull request | +| `mergeQueue` | Show merge-ready, blocked, and waiting-check items | +| `conflictQueue` | Show dirty/conflicting PRs or worktrees needing integration | + +`sessionControls.supported` lists the controls available for the current +harness. `sessionControls.blocked` explains unavailable controls, for example a +missing GitHub token, no tmux session, or a read-only adapter. + +## Sync Contract + +The sync section separates durable trackers: + +- `Linear` records project status update id, health, and whether issue creation + is blocked by workspace capacity. +- `GitHub` records the current repo, PR/issue/discussion queue counts, and the + latest merged or open PR tied to the session. +- `handoff` records the durable Markdown handoff path and whether it has been + written after the latest batch. + +This makes real-time progress tracking explicit without requiring every run to +create Linear issues or GitHub comments. When Linear issue capacity is blocked, +the status payload can still prove progress through project updates and repo +handoffs. + +## Current Implementations + +- `ecc status --json` exposes readiness, active sessions, skill runs, install + health, governance, and linked work items from the SQLite state store. +- `ecc loop-status --json --write-dir ` writes live transcript snapshots + and attention signals for long-running loops. +- `ecc session-inspect --write ` emits canonical session + snapshots from dmux and Claude-history adapters. +- `scripts/hooks/ecc-statusline.js` renders compact model, task, cost, tool, + file, duration, directory, and context pressure signals inside Claude Code. + +The `ecc.hud-status.v1` payload is the common outer contract these surfaces can +project into before ECC grows a dedicated full-screen HUD. diff --git a/docs/architecture/observability-readiness.md b/docs/architecture/observability-readiness.md index 78f42c23..c0f0ce31 100644 --- a/docs/architecture/observability-readiness.md +++ b/docs/architecture/observability-readiness.md @@ -19,6 +19,10 @@ operator needs. - Live status: `scripts/loop-status.js` can emit JSON, watch active loops, and write snapshots for dashboards or handoffs. +- HUD/status contract: `docs/architecture/hud-status-session-control.md` and + `examples/hud-status-contract.json` define the portable payload for context, + tool calls, active agents, todos, checks, cost, risk, queues, session + controls, and tracker sync. - Session traces: `scripts/session-inspect.js` can inspect Claude, dmux, and adapter-backed sessions, then write canonical snapshots. - Harness baseline: `scripts/harness-audit.js` provides a repeatable scorecard @@ -56,9 +60,11 @@ later, but only after the local event model is useful enough to trust. scorecard. 3. Run `node scripts/loop-status.js --json --write-dir .ecc/loop-status` during longer autonomous batches. -4. Run `node scripts/session-inspect.js --list-adapters` to confirm which +4. Review `examples/hud-status-contract.json` before wiring a new HUD or + operator dashboard. +5. Run `node scripts/session-inspect.js --list-adapters` to confirm which session surfaces are available. -5. Use ECC2 tool logs for risky operations, conflict analysis, and handoff +6. Use ECC2 tool logs for risky operations, conflict analysis, and handoff review before increasing autonomy. The end-state is practical: before asking ECC to run larger multi-agent loops, diff --git a/docs/releases/2.0.0-rc.1/publication-readiness.md b/docs/releases/2.0.0-rc.1/publication-readiness.md index 8066e115..847a85e4 100644 --- a/docs/releases/2.0.0-rc.1/publication-readiness.md +++ b/docs/releases/2.0.0-rc.1/publication-readiness.md @@ -45,7 +45,7 @@ Record the exact commit SHA and command output before any publication action: | Clean release branch | `git status --short --branch` | On intended release commit; no unrelated files | Pending | | Harness audit | `npm run harness:audit -- --format json` | 70/70 passing | Pending | | Adapter scorecard | `npm run harness:adapters -- --check` | PASS | Pending | -| Observability readiness | `npm run observability:ready` | 14/14 passing | Pending | +| Observability readiness | `npm run observability:ready` | 16/16 passing | Pending | | Root suite | `node tests/run-all.js` | 0 failures | Pending | | Markdown lint | `npx markdownlint-cli '**/*.md' --ignore node_modules` | 0 failures | Pending | | Package surface | `node tests/scripts/npm-publish-surface.test.js` | 0 failures | Pending | diff --git a/examples/hud-status-contract.json b/examples/hud-status-contract.json new file mode 100644 index 00000000..46867d24 --- /dev/null +++ b/examples/hud-status-contract.json @@ -0,0 +1,117 @@ +{ + "schema_version": "ecc.hud-status.v1", + "generatedAt": "2026-05-12T00:00:00.000Z", + "context": { + "harness": "codex", + "model": "gpt-5", + "repo": "affaan-m/everything-claude-code", + "branch": "main", + "worktree": "/repo/everything-claude-code", + "sessionId": "session-active", + "contextWindow": { + "remainingPct": 62, + "pressure": "normal" + } + }, + "toolCalls": { + "total": 47, + "pending": 0, + "stale": 0, + "lastTool": { + "name": "gh-pr-view", + "status": "success", + "finishedAt": "2026-05-12T00:00:00.000Z" + } + }, + "activeAgents": [ + { + "id": "worker-release-docs", + "state": "completed", + "branch": "codex/release-docs", + "worktree": "/tmp/ecc-release-docs", + "objective": "Update release readiness docs", + "handoffPath": "/tmp/ecc-release-docs/handoff.md" + } + ], + "todos": { + "inProgress": "Verify release publication matrix", + "counts": { + "pending": 2, + "inProgress": 1, + "completed": 6 + } + }, + "checks": { + "local": [ + { + "command": "npm run observability:ready", + "status": "pass" + } + ], + "remote": [ + { + "name": "CI", + "status": "pass", + "url": "https://github.com/affaan-m/everything-claude-code/actions" + } + ] + }, + "cost": { + "sessionUsd": 1.23, + "budgetUsd": 10, + "trend": "within-budget" + }, + "risk": { + "status": "attention", + "reasons": [ + "release tag not published" + ], + "dirtyWorktree": false, + "conflicts": 0, + "manualReviewRequired": true + }, + "queueState": { + "github": { + "openPullRequests": 0, + "openIssues": 0, + "openDiscussions": 0 + }, + "mergeQueue": [], + "conflictQueue": [], + "staleSalvageQueue": [ + { + "sourcePullRequest": 1310, + "status": "landed" + } + ] + }, + "sessionControls": { + "supported": [ + "create", + "resume", + "status", + "stop", + "diff", + "pr", + "mergeQueue", + "conflictQueue" + ], + "blocked": [] + }, + "sync": { + "Linear": { + "project": "ECC 2.0 GA", + "health": "atRisk", + "issueCapacityBlocked": true, + "latestStatusUpdateId": "status-update-id" + }, + "GitHub": { + "repo": "affaan-m/everything-claude-code", + "latestPullRequest": 1820 + }, + "handoff": { + "path": "~/.cluster-swarm/handoffs/ecc-update.md", + "written": true + } + } +} diff --git a/scripts/observability-readiness.js b/scripts/observability-readiness.js index 537cd942..97d4bd15 100644 --- a/scripts/observability-readiness.js +++ b/scripts/observability-readiness.js @@ -103,6 +103,13 @@ function includesAll(text, needles) { return needles.every(needle => text.includes(needle)); } +function hasObjectKeys(value, keys) { + return value + && typeof value === 'object' + && !Array.isArray(value) + && keys.every(key => Object.prototype.hasOwnProperty.call(value, key)); +} + function buildChecks(rootDir) { const packageJsonText = readText(rootDir, 'package.json'); const packageJson = safeParseJson(packageJsonText) || {}; @@ -116,6 +123,8 @@ function buildChecks(rootDir) { const sessionStoreRust = readText(rootDir, 'ecc2/src/session/store.rs'); const sessionManagerRust = readText(rootDir, 'ecc2/src/session/manager.rs'); const readinessDoc = readText(rootDir, 'docs/architecture/observability-readiness.md'); + const hudStatusContract = readText(rootDir, 'docs/architecture/hud-status-session-control.md'); + const hudStatusFixture = safeParseJson(readText(rootDir, 'examples/hud-status-contract.json')) || {}; const quickstart = readText(rootDir, 'docs/releases/2.0.0-rc.1/quickstart.md'); const releaseNotes = readText(rootDir, 'docs/releases/2.0.0-rc.1/release-notes.md'); @@ -130,6 +139,50 @@ function buildChecks(rootDir) { && includesAll(loopStatus, ['--json', '--watch', '--write-dir']), fix: 'Restore loop-status JSON/watch/write-dir support.' }, + { + id: 'hud-status-control-contract', + category: 'Live Status', + points: 2, + path: 'docs/architecture/hud-status-session-control.md', + description: 'HUD/status and session-control surfaces have a portable JSON contract', + pass: fileExists(rootDir, 'docs/architecture/hud-status-session-control.md') + && fileExists(rootDir, 'examples/hud-status-contract.json') + && includesAll(hudStatusContract, [ + 'context', + 'toolCalls', + 'activeAgents', + 'todos', + 'checks', + 'cost', + 'risk', + 'queueState', + 'create', + 'resume', + 'status', + 'stop', + 'diff', + 'pr', + 'mergeQueue', + 'conflictQueue', + 'Linear', + 'GitHub', + 'handoff' + ]) + && hudStatusFixture.schema_version === 'ecc.hud-status.v1' + && hasObjectKeys(hudStatusFixture, [ + 'context', + 'toolCalls', + 'activeAgents', + 'todos', + 'checks', + 'cost', + 'risk', + 'queueState', + 'sessionControls', + 'sync' + ]), + fix: 'Add the HUD/status session-control contract doc and example JSON fixture.' + }, { id: 'session-inspect-adapter-registry', category: 'Session Trace', diff --git a/tests/scripts/observability-readiness.test.js b/tests/scripts/observability-readiness.test.js index 87df17d3..d2e1b6bf 100644 --- a/tests/scripts/observability-readiness.test.js +++ b/tests/scripts/observability-readiness.test.js @@ -62,6 +62,24 @@ function seedMinimalRepo(rootDir, overrides = {}) { 'ecc2/src/session/store.rs': 'insert_tool_log query_tool_logs', 'ecc2/src/session/manager.rs': 'sync_tool_activity_metrics tool-usage.jsonl', 'docs/architecture/observability-readiness.md': 'node scripts/observability-readiness.js --format json', + 'docs/architecture/hud-status-session-control.md': [ + 'context toolCalls activeAgents todos checks cost risk queueState', + 'create resume status stop diff pr mergeQueue conflictQueue', + 'Linear GitHub handoff' + ].join('\n'), + 'examples/hud-status-contract.json': JSON.stringify({ + schema_version: 'ecc.hud-status.v1', + context: {}, + toolCalls: {}, + activeAgents: [], + todos: {}, + checks: {}, + cost: {}, + risk: {}, + queueState: {}, + sessionControls: {}, + sync: {} + }, null, 2), 'docs/releases/2.0.0-rc.1/quickstart.md': 'observability-readiness.md', 'docs/releases/2.0.0-rc.1/release-notes.md': 'observability-readiness.md' }; @@ -195,6 +213,23 @@ function runTests() { } })) passed++; else failed++; + if (test('missing HUD status contract fails without disturbing core tool checks', () => { + const projectRoot = createTempDir('observability-readiness-hud-fail-'); + + try { + seedMinimalRepo(projectRoot, { + 'examples/hud-status-contract.json': null + }); + const report = buildReport(projectRoot); + + assert.strictEqual(report.ready, false); + assert.ok(report.checks.some(check => check.id === 'hud-status-control-contract' && !check.pass)); + assert.ok(report.checks.some(check => check.id === 'loop-status-live-signal' && check.pass)); + } finally { + cleanup(projectRoot); + } + })) passed++; else failed++; + console.log('\nResults:'); console.log(` Passed: ${passed}`); console.log(` Failed: ${failed}`);