feat(webui): unified session/lease/lock/worktree inventory API (Closes #636) #838

Open
jcwalker3 wants to merge 1 commits from feat/issue-636-inventory-api into master
Owner

Closes #636

Phase 1 child of the Web Console epic #631. Adds the unified read-only inventory API so traffic-control and recovery views share one machine-readable source for sessions, capabilities, leases, locks, namespaces, and worktrees.

What this adds

GET /api/v1/inventory — a versioned, read-only aggregation composed into an InventorySnapshot DTO from the existing loaders plus the control-plane DB when available. Sections: sessions (CP-DB when present), role/namespace, capability summary, issue/PR leases, durable locks, worktree bindings, and hygiene anomalies. Lease owner ↔ worktree ↔ namespace are joined when the evidence supports it.

Each section is fail-soft: an unavailable subsystem degrades to a status with a reason rather than raising, and a section that could not run is never rendered as empty-and-healthy. An active lease is never reported as unowned. Collision signals surface when detectable.

Files (4, all within #636 scope)

File Change
webui/inventory.py new (952) — InventorySnapshot, section loaders, join logic, redaction
webui/app.py +35 — /api/v1/inventory route registration
tests/test_webui_inventory.py new (468) — empty, populated, partial-failure, no-false-unowned
docs/webui-local-dev.md +47 — field authority (DB vs filesystem vs Gitea) and sample payload

Acceptance criteria

AC Where
1. Sessions/leases/locks/worktrees/namespaces sections InventorySnapshot / route /api/v1/inventory
2. Unavailable subsystems degrade with reasons fail-soft section loaders
3. Collision signals when detectable hygiene-anomaly join
4. Tests: empty, populated, partial failure tests/test_webui_inventory.py
5. Docs: field authority (DB vs filesystem vs Gitea) docs/webui-local-dev.md

Non-goals honored: no lease steal/release, no worktree delete, no Gitea-history replacement. Read-only throughout; sensitive paths redacted; stale/expired leases marked; no session tokens emitted.

Provenance

The implementation was committed on this worktree in an earlier author cycle whose owning MCP session then exited, leaving the commit unpublished. This cycle recovered the durable claim through the sanctioned dead-session unpublished-claim path (gitea_lock_issue, identity jcwalker3 / prgs-author, head strictly descends from recorded base 53c2c92), re-ran the full test matrix, then published the head with gitea_publish_unpublished_issue_branch. No file copy; the single commit b7a63a5 is the work as authored, on current master.

Test evidence

Verified from the allocated worktree against master 53c2c92:

  • Focused: pytest tests/test_webui_inventory.py20 passed.
  • Full suite — 4417 passed, 11 failed, 6 skipped, 559 subtests passed.

The 11 failures are the documented pre-existing master baseline — 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. None touch webui/. This branch adds no new failures.

Canonical PR State

STATE: awaiting-review
WHO_IS_NEXT: reviewer
BLOCKED_ROLE: none
NEXT_ACTION: Review PR against issue #636 acceptance criteria 1-5 and the read-only/no-mutation non-goals
NEXT_PROMPT: Review this PR as prgs-reviewer; verify fail-soft section degradation, no-false-unowned on active leases, path redaction, and that the 11 full-suite failures match the 53c2c92 baseline; submit verdict; stop

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

Closes #636 Phase 1 child of the Web Console epic #631. Adds the unified read-only inventory API so traffic-control and recovery views share one machine-readable source for sessions, capabilities, leases, locks, namespaces, and worktrees. ## What this adds `GET /api/v1/inventory` — a versioned, read-only aggregation composed into an `InventorySnapshot` DTO from the existing loaders plus the control-plane DB when available. Sections: sessions (CP-DB when present), role/namespace, capability summary, issue/PR leases, durable locks, worktree bindings, and hygiene anomalies. Lease owner ↔ worktree ↔ namespace are joined when the evidence supports it. Each section is fail-soft: an unavailable subsystem degrades to a status with a reason rather than raising, and a section that could not run is never rendered as empty-and-healthy. An active lease is never reported as unowned. Collision signals surface when detectable. ## Files (4, all within #636 scope) | File | Change | |---|---| | `webui/inventory.py` | new (952) — `InventorySnapshot`, section loaders, join logic, redaction | | `webui/app.py` | +35 — `/api/v1/inventory` route registration | | `tests/test_webui_inventory.py` | new (468) — empty, populated, partial-failure, no-false-unowned | | `docs/webui-local-dev.md` | +47 — field authority (DB vs filesystem vs Gitea) and sample payload | ## Acceptance criteria | AC | Where | |---|---| | 1. Sessions/leases/locks/worktrees/namespaces sections | `InventorySnapshot` / route `/api/v1/inventory` | | 2. Unavailable subsystems degrade with reasons | fail-soft section loaders | | 3. Collision signals when detectable | hygiene-anomaly join | | 4. Tests: empty, populated, partial failure | `tests/test_webui_inventory.py` | | 5. Docs: field authority (DB vs filesystem vs Gitea) | `docs/webui-local-dev.md` | Non-goals honored: no lease steal/release, no worktree delete, no Gitea-history replacement. Read-only throughout; sensitive paths redacted; stale/expired leases marked; no session tokens emitted. ## Provenance The implementation was committed on this worktree in an earlier author cycle whose owning MCP session then exited, leaving the commit unpublished. This cycle recovered the durable claim through the sanctioned dead-session unpublished-claim path (`gitea_lock_issue`, identity `jcwalker3` / `prgs-author`, head strictly descends from recorded base `53c2c92`), re-ran the full test matrix, then published the head with `gitea_publish_unpublished_issue_branch`. No file copy; the single commit `b7a63a5` is the work as authored, on current master. ## Test evidence Verified from the allocated worktree against master `53c2c92`: - Focused: `pytest tests/test_webui_inventory.py` — **20 passed**. - Full suite — **4417 passed, 11 failed, 6 skipped, 559 subtests passed**. The 11 failures are the documented pre-existing master baseline — 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`. None touch `webui/`. This branch adds no new failures. ## Canonical PR State ```text STATE: awaiting-review WHO_IS_NEXT: reviewer BLOCKED_ROLE: none NEXT_ACTION: Review PR against issue #636 acceptance criteria 1-5 and the read-only/no-mutation non-goals NEXT_PROMPT: Review this PR as prgs-reviewer; verify fail-soft section degradation, no-false-unowned on active leases, path redaction, and that the 11 full-suite failures match the 53c2c92 baseline; submit verdict; stop ``` Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
jcwalker3 added 1 commit 2026-07-22 21:34:38 -05:00
Author
Owner

pr: #838
branch: feat/issue-636-inventory-api
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/issue-636-inventory-api
profile: prgs-author
session_id: unknown
phase: claimed
head_before: b7a63a5579
expires_at: 2026-07-23T08:24:08Z
reviewer_active: no

<!-- mcp-conflict-fix-lease:v1 --> pr: #838 branch: feat/issue-636-inventory-api worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/issue-636-inventory-api profile: prgs-author session_id: unknown phase: claimed head_before: b7a63a55794c977b8578f5a46eca5dd641bade68 expires_at: 2026-07-23T08:24:08Z reviewer_active: no
Author
Owner

Canonical Issue State

STATE: author-conflict-remediation-blocked
WHO_IS_NEXT: author
NEXT_ACTION: Repeat the conflict-fix merge for PR #838 from an author session that has local git-commit permission, then run the conflict-fix-gated push and require a fresh review at the new head.
NEXT_PROMPT:

Author cycle: remediate PR #838 (issue #636) conflicts. In worktree branches/issue-636-inventory-api (branch feat/issue-636-inventory-api, head b7a63a5): acquire the conflict-fix lease, `git merge --no-ff master`, resolve webui/app.py by keeping BOTH sides — #636 handlers api_inventory + api_inventory_section and routes /api/v1/inventory and /api/v1/inventory/{section}, AND master's #633 api_console_security_model handler and /api/console/security-model route — `git add webui/app.py`, `git commit --no-edit`, run assess_conflict_fix_push, push, re-run the webui + full suite, then hand to reviewer at the new exact head.

WHAT_HAPPENED: Followed the conflict-fix lease at comment 14746. Merged master (4f3a464a) into the branch in the allocated worktree; exactly one conflicted file, webui/app.py, every other path auto-merged. Both hunks are pure additive unions (this branch's #636 inventory API vs master's #633 console security-model surface). Resolution was applied and verified (ast.parse clean, all imports present), but landing a two-parent merge commit needs a local git commit + conflict-fix-gated git push (#399), both auto-denied under this cycle's headless permission mode. The in-progress merge was aborted; worktree is clean at b7a63a5. No remote mutation, no force-push, no rebase.
WHY: update_pr_branch_by_merge fail-closes on a real content conflict, and gitea_commit_files only creates single-parent API commits (cannot produce the two-parent merge that restores mergeability). The only sanctioned path is local merge + gated push, which requires git-commit permission this cycle lacks.
RELATED_PRS: #838 (this PR, blocked on author remediation); conflict originates from master #633 (merged) and #632 ADR lineage.
BLOCKERS: Headless auto-permission mode denies local git commit and git push, and no MCP tool can create a two-parent merge commit. UNBLOCK CONDITION: an author session running with local git-commit and git-push permission (interactive approval or a non-headless permission mode) re-runs the recipe in NEXT_PROMPT; the merge itself is a trivial additive union, so it completes in one pass once commit/push are permitted.
VALIDATION: Single conflict in webui/app.py; resolution ast.parse-clean with rbac_matrix/redaction_policy/console_audit and inventory imports all present; git merge --abort restored a clean worktree at b7a63a5 (git status --porcelain empty).
LAST_UPDATED_BY: prgs-author (jcwalker3)

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

## Canonical Issue State STATE: author-conflict-remediation-blocked WHO_IS_NEXT: author NEXT_ACTION: Repeat the conflict-fix merge for PR #838 from an author session that has local git-commit permission, then run the conflict-fix-gated push and require a fresh review at the new head. NEXT_PROMPT: ```text Author cycle: remediate PR #838 (issue #636) conflicts. In worktree branches/issue-636-inventory-api (branch feat/issue-636-inventory-api, head b7a63a5): acquire the conflict-fix lease, `git merge --no-ff master`, resolve webui/app.py by keeping BOTH sides — #636 handlers api_inventory + api_inventory_section and routes /api/v1/inventory and /api/v1/inventory/{section}, AND master's #633 api_console_security_model handler and /api/console/security-model route — `git add webui/app.py`, `git commit --no-edit`, run assess_conflict_fix_push, push, re-run the webui + full suite, then hand to reviewer at the new exact head. ``` WHAT_HAPPENED: Followed the conflict-fix lease at comment 14746. Merged master (4f3a464a) into the branch in the allocated worktree; exactly one conflicted file, webui/app.py, every other path auto-merged. Both hunks are pure additive unions (this branch's #636 inventory API vs master's #633 console security-model surface). Resolution was applied and verified (ast.parse clean, all imports present), but landing a two-parent merge commit needs a local git commit + conflict-fix-gated git push (#399), both auto-denied under this cycle's headless permission mode. The in-progress merge was aborted; worktree is clean at b7a63a5. No remote mutation, no force-push, no rebase. WHY: update_pr_branch_by_merge fail-closes on a real content conflict, and gitea_commit_files only creates single-parent API commits (cannot produce the two-parent merge that restores mergeability). The only sanctioned path is local merge + gated push, which requires git-commit permission this cycle lacks. RELATED_PRS: #838 (this PR, blocked on author remediation); conflict originates from master #633 (merged) and #632 ADR lineage. BLOCKERS: Headless auto-permission mode denies local `git commit` and `git push`, and no MCP tool can create a two-parent merge commit. UNBLOCK CONDITION: an author session running with local git-commit and git-push permission (interactive approval or a non-headless permission mode) re-runs the recipe in NEXT_PROMPT; the merge itself is a trivial additive union, so it completes in one pass once commit/push are permitted. VALIDATION: Single conflict in webui/app.py; resolution `ast.parse`-clean with rbac_matrix/redaction_policy/console_audit and inventory imports all present; `git merge --abort` restored a clean worktree at b7a63a5 (git status --porcelain empty). LAST_UPDATED_BY: prgs-author (jcwalker3) Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This pull request has changes conflicting with the target branch.
  • docs/webui-local-dev.md
  • webui/app.py
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/issue-636-inventory-api:feat/issue-636-inventory-api
git checkout feat/issue-636-inventory-api
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

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