docs(webui): MCP Control Plane Web Console architecture ADR (Closes #632) #796

Merged
sysadmin merged 1 commits from docs/issue-632-web-console-architecture into master 2026-07-22 06:22:11 -05:00
Owner

Closes #632

Problem

The MVP web UI (#425–#436) ships under webui/ as a read-only Starlette application with ten operator routes and a JSON export beside most of them, but the expanded console described by epic #631 has no durable architecture record: no layer contract, no authority boundary, no API versioning rule, no page map, and no statement of which phase may open a write path.

Twenty children (#632–#651) hang off #631. Without one architecture document each implementer re-derives boundaries, and the likeliest failure is not a bad view — it is a privileged action wired into the browser before the authorization and audit model of #633 exists.

What changed

Documentation only. No UI, no API, no deployment-topology change.

docs/architecture/webui-control-plane-console-architecture-adr.md (new, 244 lines).

  • §2 layers. Browser UI, HTTP route layer, domain loaders, Gitea, control-plane DB, MCP capability gates, external providers — each with what it owns and what it must not do.
  • §4 authority. Gitea records durable work; the control-plane DB coordinates live sessions and leases; task_capability_map plus gitea_resolve_task_capability remain the only mutation authority; filesystem and git hold local state; providers observe only.
  • §5 redaction boundary. Loaders may hold credentials server-side; the route layer emits redacted payloads. Two invariants are stated as non-negotiable for every child: no secrets to the browser, and no ungated mutations.
  • §6 API versioning. New console APIs land under /api/v1/.... The existing unversioned MVP exports stay as compatibility aliases for the whole of Phase 1 and may be retired no earlier than Phase 2, only after the replacing route ships and the operator doc records the swap. Breaking payload changes require /api/v2/... rather than an in-place edit.
  • §7 page map. Seventeen rows, each naming its purpose, owning child, and which MVP surface it evolves. Every current MVP route is accounted for; none is recreated.
  • §8 component ownership. All twenty children map to at least one component and exactly one phase.
  • §9 phase gates. Phase 1 read-only, Phase 2 gated actions only after #633 lands, Phase 3 orchestration, Phase 4 insights. A phase is not entered by exception.
  • §11 forbidden paths. Raw provider incidents as allocator work, browser-held tokens, process-kill recovery (#630), ungated browser mutations, policy invented in the console, and recreating MVP scope.
  • §12 approval checklist so a controller can accept or reject without reading any session history, and §13 open questions naming the issue that owns each deferred choice.

docs/webui-local-dev.md. One cross-link paragraph pointing at the ADR, placed beside the existing deployment-doc pointer.

tests/test_webui_architecture_docs.py (new). A doc gate in the style of tests/test_stable_control_runtime_policy_docs.py, covering each acceptance criterion rather than mere file existence: required sections present; versioning decision including the fate of the unversioned routes; MVP routes accounted for in the page map; every child #632–#651 present in the ownership table with a phase digit; MVP stated as foundation; all four forbidden paths named with their issue references; the approval checklist self-contained; both boundary invariants stated; open questions naming #633; the cross-link from docs/webui-local-dev.md; and no credential markers in either document.

Acceptance criteria

AC Where satisfied
1 — doc covers layers, authority, phases, API versioning, page map ADR §2, §4, §6, §7, §9
2 — each #631 child maps to an architectural component ADR §8 (twenty rows), gated by test_ac2_every_epic_child_maps_to_a_component
3 — MVP #425–#436 stated as foundation ADR header, §3, §11 item 6
4 — forbidden paths explicit ADR §11, gated by test_ac4_forbidden_paths_are_explicit
5 — controller can approve without chat history ADR §12

Tests and results

Run with venv/bin/python -m pytest from the allocated worktree.

  • New doc gate — 12 passed.
  • Web UI suite (test_webui_*, offline mode) — 117 passed, 106 subtests passed.
  • Full suite — 4252 passed, 11 failed, 6 skipped, 493 subtests passed in 5m30s.

Failure classification: the eleven failing node identifiers are byte-for-byte the ones recorded for master 620ed6e9a9550b8da2ceb82d9ab8744e8920490f in PR #794 — six in test_commit_payloads.py, two in test_issue_702_review_findings_f1_f6.py, and one each in test_mcp_server.py::TestPreflightVerification, test_post_merge_moot_lease.py, and test_reconciler_supersession_close.py. All are author-worktree binding and preflight fixtures; none touches documentation or the web UI. This branch is based on that exact commit, so the comparison is against an identical base. Stated plainly for the reviewer: a fresh baseline worktree was not re-run in this cycle, because this change adds no executable production code — the diff is two Markdown files and one new test module. Pass count moves 4240 → 4252, which is exactly the twelve new cases.

Risk

Minimal. The ADR constrains future work and changes no runtime behavior. The one enforcement surface added is the doc gate, which fails only if the ADR loses a required section or the cross-link is dropped.

Known limitations

webui/ci_paths.py triggers the web UI CI gate on webui/, tests/test_webui_*, and docs/webui*. The ADR lives under docs/architecture/, so editing the ADR alone does not trigger that gate; the new test still runs in the full suite. Widening the filter is recorded as a follow-up in ADR §13 and deliberately left out of a documentation-only change.

Adjacent work kept out of scope: #667 (restart status, impact preview, approval controls) belongs to the #655 restart-governance umbrella; the ADR notes it must reuse the #642 action class rather than adding a second restart surface.

Provenance

  • Issue: #632, parent epic Epic: MCP Control Plane Web Console (#631)
  • Branch: docs/issue-632-web-console-architecture
  • Worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/docs-issue-632-web-console-architecture
  • Published head: e33b8d37122a1153432a44dcf5213812d7e6ebf6
  • Base: master at 620ed6e9a9550b8da2ceb82d9ab8744e8920490f
  • Content was published through gitea_commit_files from the worktree, so the local worktree commit 52f6e7d and the published head are siblings carrying identical trees; the published head above is authoritative for review.
Closes #632 ## Problem The MVP web UI (#425–#436) ships under `webui/` as a read-only Starlette application with ten operator routes and a JSON export beside most of them, but the expanded console described by epic #631 has no durable architecture record: no layer contract, no authority boundary, no API versioning rule, no page map, and no statement of which phase may open a write path. Twenty children (#632–#651) hang off #631. Without one architecture document each implementer re-derives boundaries, and the likeliest failure is not a bad view — it is a privileged action wired into the browser before the authorization and audit model of #633 exists. ## What changed Documentation only. No UI, no API, no deployment-topology change. **`docs/architecture/webui-control-plane-console-architecture-adr.md` (new, 244 lines).** - **§2 layers.** Browser UI, HTTP route layer, domain loaders, Gitea, control-plane DB, MCP capability gates, external providers — each with what it owns and what it must not do. - **§4 authority.** Gitea records durable work; the control-plane DB coordinates live sessions and leases; `task_capability_map` plus `gitea_resolve_task_capability` remain the only mutation authority; filesystem and git hold local state; providers observe only. - **§5 redaction boundary.** Loaders may hold credentials server-side; the route layer emits redacted payloads. Two invariants are stated as non-negotiable for every child: no secrets to the browser, and no ungated mutations. - **§6 API versioning.** New console APIs land under `/api/v1/...`. The existing unversioned MVP exports stay as compatibility aliases for the whole of Phase 1 and may be retired no earlier than Phase 2, only after the replacing route ships and the operator doc records the swap. Breaking payload changes require `/api/v2/...` rather than an in-place edit. - **§7 page map.** Seventeen rows, each naming its purpose, owning child, and which MVP surface it evolves. Every current MVP route is accounted for; none is recreated. - **§8 component ownership.** All twenty children map to at least one component and exactly one phase. - **§9 phase gates.** Phase 1 read-only, Phase 2 gated actions only after #633 lands, Phase 3 orchestration, Phase 4 insights. A phase is not entered by exception. - **§11 forbidden paths.** Raw provider incidents as allocator work, browser-held tokens, process-kill recovery (#630), ungated browser mutations, policy invented in the console, and recreating MVP scope. - **§12 approval checklist** so a controller can accept or reject without reading any session history, and **§13 open questions** naming the issue that owns each deferred choice. **`docs/webui-local-dev.md`.** One cross-link paragraph pointing at the ADR, placed beside the existing deployment-doc pointer. **`tests/test_webui_architecture_docs.py` (new).** A doc gate in the style of `tests/test_stable_control_runtime_policy_docs.py`, covering each acceptance criterion rather than mere file existence: required sections present; versioning decision including the fate of the unversioned routes; MVP routes accounted for in the page map; every child #632–#651 present in the ownership table with a phase digit; MVP stated as foundation; all four forbidden paths named with their issue references; the approval checklist self-contained; both boundary invariants stated; open questions naming #633; the cross-link from `docs/webui-local-dev.md`; and no credential markers in either document. ## Acceptance criteria | AC | Where satisfied | |----|-----------------| | 1 — doc covers layers, authority, phases, API versioning, page map | ADR §2, §4, §6, §7, §9 | | 2 — each #631 child maps to an architectural component | ADR §8 (twenty rows), gated by `test_ac2_every_epic_child_maps_to_a_component` | | 3 — MVP #425–#436 stated as foundation | ADR header, §3, §11 item 6 | | 4 — forbidden paths explicit | ADR §11, gated by `test_ac4_forbidden_paths_are_explicit` | | 5 — controller can approve without chat history | ADR §12 | ## Tests and results Run with `venv/bin/python -m pytest` from the allocated worktree. - New doc gate — **12 passed**. - Web UI suite (`test_webui_*`, offline mode) — **117 passed, 106 subtests passed**. - Full suite — **4252 passed, 11 failed, 6 skipped, 493 subtests passed** in 5m30s. Failure classification: the eleven failing node identifiers are byte-for-byte the ones recorded for master `620ed6e9a9550b8da2ceb82d9ab8744e8920490f` in PR #794 — six in `test_commit_payloads.py`, two in `test_issue_702_review_findings_f1_f6.py`, and one each in `test_mcp_server.py::TestPreflightVerification`, `test_post_merge_moot_lease.py`, and `test_reconciler_supersession_close.py`. All are author-worktree binding and preflight fixtures; none touches documentation or the web UI. This branch is based on that exact commit, so the comparison is against an identical base. Stated plainly for the reviewer: a fresh baseline worktree was **not** re-run in this cycle, because this change adds no executable production code — the diff is two Markdown files and one new test module. Pass count moves 4240 → 4252, which is exactly the twelve new cases. ## Risk Minimal. The ADR constrains future work and changes no runtime behavior. The one enforcement surface added is the doc gate, which fails only if the ADR loses a required section or the cross-link is dropped. ## Known limitations `webui/ci_paths.py` triggers the web UI CI gate on `webui/`, `tests/test_webui_*`, and `docs/webui*`. The ADR lives under `docs/architecture/`, so editing the ADR alone does not trigger that gate; the new test still runs in the full suite. Widening the filter is recorded as a follow-up in ADR §13 and deliberately left out of a documentation-only change. Adjacent work kept out of scope: #667 (restart status, impact preview, approval controls) belongs to the #655 restart-governance umbrella; the ADR notes it must reuse the #642 action class rather than adding a second restart surface. ## Provenance - Issue: #632, parent epic #631 - Branch: `docs/issue-632-web-console-architecture` - Worktree: `/Users/jasonwalker/Development/Gitea-Tools/branches/docs-issue-632-web-console-architecture` - Published head: `e33b8d37122a1153432a44dcf5213812d7e6ebf6` - Base: master at `620ed6e9a9550b8da2ceb82d9ab8744e8920490f` - Content was published through `gitea_commit_files` from the worktree, so the local worktree commit `52f6e7d` and the published head are siblings carrying identical trees; the published head above is authoritative for review.
jcwalker3 added 1 commit 2026-07-22 04:53:40 -05:00
Adds the durable architecture record epic #631 lacked: layer contract,
authority boundaries, the redaction boundary, /api/v1 versioning with a
compatibility rule for the existing unversioned MVP exports, a target page
map, per-child component ownership for all twenty children (#632-#651),
phase gates, and explicit forbidden paths.

Documentation only. No UI, API, or deployment change.

- docs/architecture/webui-control-plane-console-architecture-adr.md (new)
- docs/webui-local-dev.md: cross-link to the ADR
- tests/test_webui_architecture_docs.py: doc gate for the acceptance
  criteria and the cross-link (12 cases)

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Author
Owner

CTH: Author Handoff

Status: published_awaiting_independent_review
Next owner: reviewer (prgs-reviewer / sysadmin)
Current blocker: none
Decision: PR #796 is documentation-only ADR for #632; ready for independent review
Proof: published head e33b8d37122a1153432a44dcf5213812d7e6ebf6 on docs/issue-632-web-console-architecture; base master; Closes #632
Next action: independent formal review at exact head e33b8d37122a1153432a44dcf5213812d7e6ebf6
Ready-to-paste prompt: see NEXT_PROMPT below

Canonical Issue State

STATE: pr_open_awaiting_review
WHO_IS_NEXT: reviewer
NEXT_ACTION: formal independent review of PR #796 at head e33b8d3712
NEXT_PROMPT:

Review PR #796 (Closes #632) on prgs Scaled-Tech-Consulting/Gitea-Tools as prgs-reviewer.
Pin head e33b8d37122a1153432a44dcf5213812d7e6ebf6 on docs/issue-632-web-console-architecture targeting master.
Scope is docs + doc-gate tests only; verify ADR acceptance criteria and test_webui_architecture_docs.
Submit one formal APPROVE or REQUEST_CHANGES; do not merge.

WHAT_HAPPENED: Canonical author handoff posted for already-published PR #796 (incomplete handoff). Implementation and validation evidence are in the PR body.
WHY: Queue hygiene — open PR lacked CTH handoff so reviewer ownership was unclear.
RELATED_PRS: #796 (this PR); parent epic #631
BLOCKERS: none
VALIDATION: See PR body — new doc gate 12 passed; web UI suite 117 passed; full suite 4252 passed / 11 baseline fail.
LAST_UPDATED_BY: jcwalker3 (prgs-author)
REPOSITORY: Scaled-Tech-Consulting/Gitea-Tools
ISSUE: #632
PR: #796
HEAD_SHA: e33b8d3712
BASE_BRANCH: master
ACTING_ROLE: author
ACTING_IDENTITY: jcwalker3

<!-- cth:v1 --> ## CTH: Author Handoff Status: published_awaiting_independent_review Next owner: reviewer (prgs-reviewer / sysadmin) Current blocker: none Decision: PR #796 is documentation-only ADR for #632; ready for independent review Proof: published head `e33b8d37122a1153432a44dcf5213812d7e6ebf6` on `docs/issue-632-web-console-architecture`; base master; Closes #632 Next action: independent formal review at exact head `e33b8d37122a1153432a44dcf5213812d7e6ebf6` Ready-to-paste prompt: see NEXT_PROMPT below ## Canonical Issue State STATE: pr_open_awaiting_review WHO_IS_NEXT: reviewer NEXT_ACTION: formal independent review of PR #796 at head e33b8d37122a1153432a44dcf5213812d7e6ebf6 NEXT_PROMPT: ```text Review PR #796 (Closes #632) on prgs Scaled-Tech-Consulting/Gitea-Tools as prgs-reviewer. Pin head e33b8d37122a1153432a44dcf5213812d7e6ebf6 on docs/issue-632-web-console-architecture targeting master. Scope is docs + doc-gate tests only; verify ADR acceptance criteria and test_webui_architecture_docs. Submit one formal APPROVE or REQUEST_CHANGES; do not merge. ``` WHAT_HAPPENED: Canonical author handoff posted for already-published PR #796 (incomplete handoff). Implementation and validation evidence are in the PR body. WHY: Queue hygiene — open PR lacked CTH handoff so reviewer ownership was unclear. RELATED_PRS: #796 (this PR); parent epic #631 BLOCKERS: none VALIDATION: See PR body — new doc gate 12 passed; web UI suite 117 passed; full suite 4252 passed / 11 baseline fail. LAST_UPDATED_BY: jcwalker3 (prgs-author) REPOSITORY: Scaled-Tech-Consulting/Gitea-Tools ISSUE: #632 PR: #796 HEAD_SHA: e33b8d37122a1153432a44dcf5213812d7e6ebf6 BASE_BRANCH: master ACTING_ROLE: author ACTING_IDENTITY: jcwalker3
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #796
issue: #632
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 50914-11d3fdcfec3f
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-796
phase: claimed
candidate_head: e33b8d3712
target_branch: master
target_branch_sha: 5032965e3a
last_activity: 2026-07-22T11:20:38Z
expires_at: 2026-07-22T11:30:38Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #796 issue: #632 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 50914-11d3fdcfec3f worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-796 phase: claimed candidate_head: e33b8d37122a1153432a44dcf5213812d7e6ebf6 target_branch: master target_branch_sha: 5032965e3a39654f1d65b2a58f25931bc72ff17b last_activity: 2026-07-22T11:20:38Z expires_at: 2026-07-22T11:30:38Z blocker: none
sysadmin approved these changes 2026-07-22 06:21:19 -05:00
sysadmin left a comment
Owner

Canonical PR State

STATE: approved
WHO_IS_NEXT: merger
NEXT_ACTION: Merge PR #796 via gated gitea_merge_pr with expected_head_sha e33b8d3712 and confirmation MERGE PR 796.
NEXT_PROMPT:

Merge PR #796 (docs ADR #632) at head e33b8d37122a1153432a44dcf5213812d7e6ebf6 using prgs-merger after re-checking eligibility and approval_at_current_head. confirmation=MERGE PR 796. expected_changed_files: docs/architecture/webui-control-plane-console-architecture-adr.md, docs/webui-local-dev.md, tests/test_webui_architecture_docs.py.

WHAT_HAPPENED: Independent review of next eligible open PR #796 after skipping #794 and #795 (live REQUEST_CHANGES at unchanged heads). Docs-only ADR + cross-link + doc-gate tests. Validation passed in branches/review-pr-796 via native MCP.
WHY: Scope matches #632 only; ACs 1-5 met by ADR and gated by tests; no production runtime change; layer/authority/redaction/versioning/page map/phase gates/forbidden paths explicit.
ISSUE: #632
HEAD_SHA: e33b8d3712
REVIEW_STATUS: approved / approval_at_current_head
MERGE_READY: true
BLOCKERS: none
VALIDATION: pytest tests/test_webui_architecture_docs.py 12 passed; pytest -k webui 117 passed 106 subtests; worktree clean; not already-landed; mergeable true; author jcwalker3 != sysadmin
NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; token_fingerprint=73992c6535105066
LAST_UPDATED_BY: sysadmin (prgs-reviewer)


Review summary

Approve. Documentation-only change that correctly closes #632 without over-claiming epic #631.

Diff: ADR (layers, authority, redaction invariants, /api/v1 versioning, page map, all children #632-#651 with phases, phase gates, forbidden paths, checklist), webui-local-dev cross-link, doc-gate tests.

Validation: 12/12 architecture tests; 117 webui tests green.

## Canonical PR State STATE: approved WHO_IS_NEXT: merger NEXT_ACTION: Merge PR #796 via gated gitea_merge_pr with expected_head_sha e33b8d37122a1153432a44dcf5213812d7e6ebf6 and confirmation MERGE PR 796. NEXT_PROMPT: ```text Merge PR #796 (docs ADR #632) at head e33b8d37122a1153432a44dcf5213812d7e6ebf6 using prgs-merger after re-checking eligibility and approval_at_current_head. confirmation=MERGE PR 796. expected_changed_files: docs/architecture/webui-control-plane-console-architecture-adr.md, docs/webui-local-dev.md, tests/test_webui_architecture_docs.py. ``` WHAT_HAPPENED: Independent review of next eligible open PR #796 after skipping #794 and #795 (live REQUEST_CHANGES at unchanged heads). Docs-only ADR + cross-link + doc-gate tests. Validation passed in branches/review-pr-796 via native MCP. WHY: Scope matches #632 only; ACs 1-5 met by ADR and gated by tests; no production runtime change; layer/authority/redaction/versioning/page map/phase gates/forbidden paths explicit. ISSUE: #632 HEAD_SHA: e33b8d37122a1153432a44dcf5213812d7e6ebf6 REVIEW_STATUS: approved / approval_at_current_head MERGE_READY: true BLOCKERS: none VALIDATION: pytest tests/test_webui_architecture_docs.py 12 passed; pytest -k webui 117 passed 106 subtests; worktree clean; not already-landed; mergeable true; author jcwalker3 != sysadmin NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; token_fingerprint=73992c6535105066 LAST_UPDATED_BY: sysadmin (prgs-reviewer) --- ## Review summary Approve. Documentation-only change that correctly closes #632 without over-claiming epic #631. Diff: ADR (layers, authority, redaction invariants, /api/v1 versioning, page map, all children #632-#651 with phases, phase gates, forbidden paths, checklist), webui-local-dev cross-link, doc-gate tests. Validation: 12/12 architecture tests; 117 webui tests green.
Owner

adopted_at: 2026-07-22T11:21:56Z
adopted_by_identity: sysadmin
adopted_by_profile: prgs-merger
adopted_from_session_id: 50914-11d3fdcfec3f
adopted_from_profile: prgs-reviewer
adopted_from_reviewer_identity: sysadmin
adopted_from_comment_id: 14130
adoption_reason: merger-handoff-approved-head

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #796
issue: #632
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 50911-62ac4e098ef9
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-796
phase: adopted
candidate_head: e33b8d3712
target_branch: master
target_branch_sha: 5032965e3a
last_activity: 2026-07-22T11:21:56Z
expires_at: 2026-07-22T11:31:56Z
blocker: none

<!-- mcp-review-lease-adoption:v1 --> adopted_at: 2026-07-22T11:21:56Z adopted_by_identity: sysadmin adopted_by_profile: prgs-merger adopted_from_session_id: 50914-11d3fdcfec3f adopted_from_profile: prgs-reviewer adopted_from_reviewer_identity: sysadmin adopted_from_comment_id: 14130 adoption_reason: merger-handoff-approved-head <!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #796 issue: #632 reviewer_identity: sysadmin profile: prgs-merger session_id: 50911-62ac4e098ef9 worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-796 phase: adopted candidate_head: e33b8d37122a1153432a44dcf5213812d7e6ebf6 target_branch: master target_branch_sha: 5032965e3a39654f1d65b2a58f25931bc72ff17b last_activity: 2026-07-22T11:21:56Z expires_at: 2026-07-22T11:31:56Z blocker: none
sysadmin merged commit 0b29404031 into master 2026-07-22 06:22:11 -05:00
Owner

Stale #332 review-decision lock cleanup (#594)

Status: APPLIED

Manual deletion of session-state files is not the workflow.
This path only clears a lock when the referenced PR is merged/closed.

## Stale #332 review-decision lock cleanup (#594) Status: **APPLIED** - actor: `sysadmin` - profile: `prgs-merger` - timestamp: `2026-07-22T11:22:13.265454+00:00` - last terminal: `approve` on PR #796 - PR state: `closed` (merged=True) - merge_commit_sha: `0b294040314ecf661dcd010cb55a05d923233a95` - prior live_mutations_count: `3` - prior profile_identity: `prgs-reviewer` Manual deletion of session-state files is **not** the workflow. This path only clears a lock when the referenced PR is merged/closed.
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#796