Skip to content

feat(community): add collaborator community view (stats + leaderboard + kanban)#2042

Open
hognek wants to merge 5 commits into
jaylfc:devfrom
hognek:feat/collab-f-community-view
Open

feat(community): add collaborator community view (stats + leaderboard + kanban)#2042
hognek wants to merge 5 commits into
jaylfc:devfrom
hognek:feat/collab-f-community-view

Conversation

@hognek

@hognek hognek commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements Milestone F (Collaborator Community View) from #2021.

Deferred (per review)

Verification

  • SPA build: npm run build passes clean
  • Python tests: 10/10 pass (incl. cross-user ownership)
  • vitest: 4/4 pass (loading, error, empty, populated render)

Refs: #2021, #2012

…ard, and live kanban

- Widen member_kind validation in project_store to include 'human'
- Add community projection endpoints (snapshot + stats/leaderboard)
  at GET /api/projects/{id}/community/{snapshot,stats}
- Build CommunityView React component with overview stats, leaderboard
  table, read-only kanban columns, and activity feed
- Add 'community' tab to ProjectWorkspace
- Add community API types and fetch functions to projects.ts
- Add unit tests for leaderboard rollup function

Refs: jaylfc#2021 (Collab F, Milestone F — community view)
@hognek
hognek marked this pull request as ready for review July 19, 2026 11:25
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds read-only community snapshot and stats APIs, leaderboard aggregation, human member handling, and a desktop Community tab with stats, leaderboard, kanban, and activity views.

Changes

Community View

Layer / File(s) Summary
Community projection API
tinyagentos/routes/community.py, tinyagentos/routes/__init__.py, tinyagentos/projects/project_store.py, desktop/src/lib/projects.ts, data/hub/identity.json
Adds allowlisted snapshot and stats endpoints, leaderboard aggregation, router registration, community payload types, human member normalization, and hub identity data.
Desktop dashboard integration
desktop/src/apps/ProjectsApp/CommunityView.tsx, desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx, desktop/src/apps/ProjectsApp/ProjectsApp.module.css
Adds the Community tab and renders fetched project statistics, contributor leaderboard, read-only kanban tasks, and recent activity with loading and error states.
Endpoint and leaderboard validation
tests/test_community.py
Tests snapshot and stats responses, missing projects, task sanitization, and leaderboard aggregation behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CommunityView
  participant projectsApi
  participant community_snapshot
  participant ProjectStore
  CommunityView->>projectsApi: request community.snapshot(projectId)
  projectsApi->>community_snapshot: GET snapshot endpoint
  community_snapshot->>ProjectStore: read project, tasks, and audit events
  ProjectStore-->>community_snapshot: project data and events
  community_snapshot-->>projectsApi: sanitized snapshot payload
  projectsApi-->>CommunityView: render CommunitySnapshot
Loading

Possibly related issues

Possibly related PRs

  • jaylfc/taOS#941 — Shares changes to the workspace tab union, tab list, and rendering logic.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: a new community view with stats, leaderboard, and kanban integration.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

gitar-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

Comment thread tinyagentos/routes/community.py Outdated
return {k: v for k, v in task.items() if k in _TASK_ALLOWLIST}


def _parse_labels(task: dict) -> list[str]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Dead code — _parse_labels is defined but never called anywhere in the PR.

The task store already parses labels via json.loads in _row_to_task, so task_store.list_tasks returns lists, and the projection passes them through untouched. This function is unreachable. Either remove it or actually use it to normalize labels (e.g. when the store returns a raw string fallback). Right now it's misleading dead code that implies labels are handled here.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread tinyagentos/routes/community.py Outdated
- project metadata (name, slug, description, status)
- board tasks (id, title, status, claimant, labels, timestamps)
- contribution stats (per-contributor claim/close counts, leaderboard)
- recent activity feed (last 50 board-audit events)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Docstring says "last 50 board-audit events" but the code fetches limit=500 (line 109) and the activity feed is sliced to the first 20 (audit_events[:20], line 121).

This is a documentation/implementation mismatch. The feed is newest-first (board_audit returns ORDER BY rowid DESC) and capped at 20, not 50. Update the docstring (and the recent_activity count semantics) to match the actual behavior so future maintainers aren't misled.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

raise ValueError(f"invalid member_kind: {member_kind}")
if member_kind == "human":
# Human members are remote collaborators — no agent lifecycle fields.
memory_seed = "none"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: add_member silently overrides caller-supplied memory_seed and source_agent_id to "none"/None for human members.

This is reasonable for the human-collaborator model, but it silently discards any non-default values a caller passes. If a future caller passes a populated source_agent_id expecting it to be stored, it will be dropped with no error. Consider either documenting this override in the function docstring, or asserting the inputs are None/"none" when member_kind=="human" so the silent discard is at least visible in tests.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
tinyagentos/routes/community.py 74 Admin bypass grants any admin read access to every user's community projection (task board, leaderboard, activity feed) for projects they don't own. Matches the existing projects.py owner/admin pattern but widens blast radius for a privacy-sensitive projection. Fix: drop not user.is_admin to owner-scope the view, or gate/log cross-user admin access.
Previously-flagged issues — now RESOLVED in this diff
  • data/hub/identity.json — Private keys no longer tracked; data/hub/ added to .gitignore (file absent at HEAD). CRITICAL resolved.
  • tinyagentos/routes/community.pyproject_store.get(...) replaced with get_project(...) (CodeRabbit CRITICAL resolved).
  • tinyagentos/routes/community.py_parse_labels dead code removed.
  • tinyagentos/routes/community.py — Docstring corrected (500 events fetched, 20 rendered).
  • tinyagentos/projects/project_store.pyadd_member human override now logs a warning.
  • desktop/src/apps/ProjectsApp/CommunityView.tsx — Unknown task statuses now render as extra kanban columns (no silent drop).
  • tests/test_community.py — Vacuous conditional assertion replaced with direct assertion.
  • Cross-user ownership now returns masked 404 (no existence leak).
Files Reviewed (full PR — 11 files)
  • tinyagentos/routes/community.py - 1 issue (WARNING)
  • tinyagentos/projects/project_store.py - resolved
  • tinyagentos/routes/__init__.py - resolved
  • desktop/src/lib/projects.ts - ok
  • desktop/src/apps/ProjectsApp/CommunityView.tsx - resolved
  • desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx - ok
  • desktop/src/apps/ProjectsApp/ProjectsApp.module.css - ok
  • desktop/src/apps/ProjectsApp/__tests__/CommunityView.test.tsx - ok
  • tests/test_community.py - resolved
  • .gitignore - resolved
  • desktop/package-lock.json - ok

Fix these issues in Kilo Cloud

Previous Review Summaries (3 snapshots, latest commit 2f74a30)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 2f74a30)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
data/hub/identity.json 1 Private signing/encryption keys committed to the repo (not gitignored) — rotate and remove from history
Previously-flagged issues — now RESOLVED in this incremental diff
  • tinyagentos/routes/community.pyproject_store.get(...) was a nonexistent method; both community_snapshot (line 71) and community_stats (line 135) now call project_store.get_project(...), fixing the AttributeError that broke every request. Verified get_project exists at tinyagentos/projects/project_store.py:165.
Files Reviewed (incremental: 1 file)
  • tinyagentos/routes/community.py - resolved (the only file changed since previous review commit d32de75)

Fix these issues in Kilo Cloud

Previous review (commit d32de75)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
data/hub/identity.json 1 Private signing/encryption keys committed to the repo (not gitignored) — rotate and remove from history
Previously-flagged issues — now RESOLVED in this incremental diff
  • tinyagentos/routes/community.py_parse_labels dead code removed.
  • tinyagentos/routes/community.py — docstring corrected from "last 50" to "last 500, rendered as most-recent 20".
  • tinyagentos/projects/project_store.pyadd_member now logs a warning when overriding memory_seed/source_agent_id for human members (was silently discarding).
  • tinyagentos/routes/community.pytask_store attribute renamed to project_task_store (verified present on app.state in app.py).
Still-open pre-existing issue (not changed by this diff, active CodeRabbit comment)
  • tinyagentos/routes/community.py (lines 71, 135) — project_store.get(...) should be get_project(...); ProjectStore exposes only get_project, so both community routes raise AttributeError at runtime. Not part of this incremental change; remains unaddressed.
Files Reviewed (incremental: 3 files)
  • data/hub/identity.json - 1 issue (CRITICAL)
  • tinyagentos/projects/project_store.py - resolved
  • tinyagentos/routes/community.py - resolved

Fix these issues in Kilo Cloud

Previous review (commit eac6503)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 3
Issue Details (click to expand)

SUGGESTION

File Line Issue
tinyagentos/routes/community.py 44 _parse_labels is dead code — defined but never called; task store already parses labels
tinyagentos/routes/community.py 77 Docstring claims "last 50 board-audit events" but code uses limit=500 and slices feed to 20
tinyagentos/projects/project_store.py 268 add_member silently overrides memory_seed/source_agent_id for human members, discarding caller values
Files Reviewed (8 files)
  • desktop/src/apps/ProjectsApp/CommunityView.tsx
  • desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx
  • desktop/src/apps/ProjectsApp/ProjectsApp.module.css
  • desktop/src/lib/projects.ts
  • tests/test_community.py
  • tinyagentos/projects/project_store.py
  • tinyagentos/routes/__init__.py
  • tinyagentos/routes/community.py

Fix these issues in Kilo Cloud


Reviewed by hy3:free · Input: 89.4K · Output: 5.7K · Cached: 752.2K

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

- Remove dead _parse_labels function (task store already parses labels)
- Fix docstring: actual fetch is 500 events, feed truncated to 20
- Add logger.warning when overriding memory_seed/source_agent_id
  for human members in add_member

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx (1)

105-112: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Community tab isn't reachable on mobile.

mobileTabOrder (which drives tabPills for the mobile pill nav) wasn't updated to include "community", unlike the desktop TABS array. Mobile users have no in-app control to reach the new tab (only a deep link would work).

🐛 Proposed fix
-  const mobileTabOrder: Tab[] = ["workspace", "messages", "board", "tasks", "canvas", "files", "members", "activity", "decisions", "routines"];
+  const mobileTabOrder: Tab[] = ["workspace", "messages", "board", "tasks", "canvas", "files", "members", "activity", "decisions", "routines", "community"];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx` around lines 105 - 112,
Update the mobileTabOrder array in ProjectWorkspace so it includes the
"community" tab, matching the available desktop TABS entries and ensuring it is
exposed through the existing tabPills mobile navigation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@desktop/src/apps/ProjectsApp/CommunityView.tsx`:
- Around line 157-166: Update the columns construction in CommunityView to
retain the existing statusOrder columns while appending any task statuses not
included in that list. Derive unknown statuses from tasksByStatus, ensure each
appears only once, and preserve the current filtering of empty status groups so
every task remains visible on the board.

In `@tests/test_community.py`:
- Around line 144-150: The leaderboard test conditionally skips all checks when
body["leaderboard"] is empty. In the leaderboard assertions near test_community,
assert that body["leaderboard"] is non-empty, then assign its first entry and
run the existing actor, claims, closes, and total assertions unconditionally,
matching test_community_snapshot_with_tasks.

In `@tinyagentos/routes/community.py`:
- Around line 84-88: Replace the nonexistent project_store.get call with
project_store.get_project in the affected community route, and apply the same
method-name correction in community_stats. Preserve the existing 404 and
authorization checks.
- Line 77: Update the community endpoint docstring to state that the recent
activity feed returns the last 20 board-audit events, matching the
audit_events[:20] limit and its inline comment. Apply the same correction to the
corresponding documentation around the additional referenced section.

---

Outside diff comments:
In `@desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx`:
- Around line 105-112: Update the mobileTabOrder array in ProjectWorkspace so it
includes the "community" tab, matching the available desktop TABS entries and
ensuring it is exposed through the existing tabPills mobile navigation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5eca8580-4fb3-46dc-9b04-c5766ba1bd35

📥 Commits

Reviewing files that changed from the base of the PR and between 91af53e and eac6503.

📒 Files selected for processing (8)
  • desktop/src/apps/ProjectsApp/CommunityView.tsx
  • desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx
  • desktop/src/apps/ProjectsApp/ProjectsApp.module.css
  • desktop/src/lib/projects.ts
  • tests/test_community.py
  • tinyagentos/projects/project_store.py
  • tinyagentos/routes/__init__.py
  • tinyagentos/routes/community.py

Comment thread desktop/src/apps/ProjectsApp/CommunityView.tsx
Comment thread tests/test_community.py Outdated
Comment thread tinyagentos/routes/community.py Outdated
- project metadata (name, slug, description, status)
- board tasks (id, title, status, claimant, labels, timestamps)
- contribution stats (per-contributor claim/close counts, leaderboard)
- recent activity feed (last 50 board-audit events)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Docstring says "last 50", code slices to 20.

The endpoint docstring claims the recent activity feed returns the "last 50 board-audit events", but the implementation caps it at audit_events[:20] (matching the inline comment "last 20 events"). Align the docstring with actual behavior.

Also applies to: 112-122

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tinyagentos/routes/community.py` at line 77, Update the community endpoint
docstring to state that the recent activity feed returns the last 20 board-audit
events, matching the audit_events[:20] limit and its inline comment. Apply the
same correction to the corresponding documentation around the additional
referenced section.

Comment thread tinyagentos/routes/community.py Outdated
… access

The community route referenced request.app.state.task_store, but the
lifespan registers the attribute as project_task_store (matching the
ProjectTaskStore class name). This caused 5/8 community tests to fail
with KeyError/AttributeError on CI.

Also fixes the doc-gate by documenting why the structural changes
(adding desktop/src/apps/ProjectsApp/CommunityView.tsx and
tinyagentos/routes/community.py) don't need README.md or
docs/agent-coordination.md updates: the Community View is a new
feature scoped under Projects, not a standalone desktop app or a
cross-cutting agent-coordination API.

Docs-Reviewed: Community View is a Projects sub-feature, not a standalone app; route is an internal projection endpoint scoped to project boards, not part of the agent-coordination surface

Refs: jaylfc#2042
hognek added a commit to hognek/tinyagentos that referenced this pull request Jul 19, 2026
- Remove dead _parse_labels function (task store already parses labels)
- Fix docstring: actual fetch is 500 events, feed truncated to 20
- Add logger.warning when overriding memory_seed/source_agent_id
  for human members in add_member
hognek added a commit to hognek/tinyagentos that referenced this pull request Jul 19, 2026
… access

The community route referenced request.app.state.task_store, but the
lifespan registers the attribute as project_task_store (matching the
ProjectTaskStore class name). This caused 5/8 community tests to fail
with KeyError/AttributeError on CI.

Also fixes the doc-gate by documenting why the structural changes
(adding desktop/src/apps/ProjectsApp/CommunityView.tsx and
tinyagentos/routes/community.py) don't need README.md or
docs/agent-coordination.md updates: the Community View is a new
feature scoped under Projects, not a standalone desktop app or a
cross-cutting agent-coordination API.

Docs-Reviewed: Community View is a Projects sub-feature, not a standalone app; route is an internal projection endpoint scoped to project boards, not part of the agent-coordination surface

Refs: jaylfc#2042
Comment thread data/hub/identity.json Outdated
@@ -0,0 +1 @@
{"signing_private": "1cf1ac0cbeea7bbd6a68bf38abfaa683800d4dea498079c83d154b427d56ea14", "signing_public": "0012434ac9e5bc51c7ca8d0e7de5ad9c59faf2a6afa92dec00b935dfd2e85377", "encryption_private": "40a212e227c8897dadf6548bf542d0be09031f595e26b3a6fce5ecdda02e1953", "encryption_public": "91a91b4d7ac1ba8ad7d9fc1a4bd56beea659d60298f93da0ca0f1e3d376f3947", "created_at": 1784460139.0949676} No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Private cryptographic keys committed to the repository.

This new file contains signing_private and encryption_private — the secret/private halves of the hub identity keypair. Committing private keys to git history exposes them permanently (even if later removed, they remain in history). Anyone with repo access can impersonate the hub's signing/encryption identity.

Recommended fix:

  • Remove this file from the commit and add it to .gitignore.
  • Load identity.json from a local/secrets path at runtime (e.g. env-var or mounted secret), never from the repo.
  • If these keys were already pushed, rotate them — treat the private material as compromised and generate a new identity.
  • Scrub the key from history (e.g. git filter-repo) before merge if it has reached a shared remote.

Note: data/hub/identity.json is currently NOT gitignored, so it will be tracked.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
tinyagentos/routes/community.py (1)

71-71: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Fix project_store.get method calls to get_project.

ProjectStore only exposes the get_project method. Calling .get() will result in an AttributeError on every request.

  • tinyagentos/routes/community.py#L71-L71: Change await project_store.get(project_id) to await project_store.get_project(project_id).
  • tinyagentos/routes/community.py#L135-L135: Change await project_store.get(project_id) to await project_store.get_project(project_id).
🐛 Proposed fixes

For community_snapshot (Line 71):

-    project = await project_store.get(project_id)
+    project = await project_store.get_project(project_id)

For community_stats (Line 135):

-    project = await project_store.get(project_id)
+    project = await project_store.get_project(project_id)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tinyagentos/routes/community.py` at line 71, Replace the invalid
project_store.get calls with project_store.get_project in both
community_snapshot (tinyagentos/routes/community.py:71-71) and community_stats
(tinyagentos/routes/community.py:135-135), preserving the existing await and
project_id argument.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@data/hub/identity.json`:
- Line 1: Remove data/hub/identity.json from version control and add its path or
parent directory to .gitignore so generated identity state is not committed.
Treat the exposed signing_private and encryption_private values as compromised
and rotate them wherever they may have been used; only retain replacement dummy
keys in explicitly documented test fixtures if testing requires them.

---

Duplicate comments:
In `@tinyagentos/routes/community.py`:
- Line 71: Replace the invalid project_store.get calls with
project_store.get_project in both community_snapshot
(tinyagentos/routes/community.py:71-71) and community_stats
(tinyagentos/routes/community.py:135-135), preserving the existing await and
project_id argument.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 63fffac0-f078-4934-96a5-c43cc5555614

📥 Commits

Reviewing files that changed from the base of the PR and between eac6503 and d32de75.

📒 Files selected for processing (3)
  • data/hub/identity.json
  • tinyagentos/projects/project_store.py
  • tinyagentos/routes/community.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tinyagentos/projects/project_store.py

Comment thread data/hub/identity.json Outdated
@@ -0,0 +1 @@
{"signing_private": "1cf1ac0cbeea7bbd6a68bf38abfaa683800d4dea498079c83d154b427d56ea14", "signing_public": "0012434ac9e5bc51c7ca8d0e7de5ad9c59faf2a6afa92dec00b935dfd2e85377", "encryption_private": "40a212e227c8897dadf6548bf542d0be09031f595e26b3a6fce5ecdda02e1953", "encryption_public": "91a91b4d7ac1ba8ad7d9fc1a4bd56beea659d60298f93da0ca0f1e3d376f3947", "created_at": 1784460139.0949676} No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Remove hardcoded private keys from source control.

This file contains sensitive cryptographic keys (signing_private, encryption_private). Committing private keys to the repository is a critical security vulnerability.

If this is a dynamically generated local state file, please remove it from version control and add its path (data/hub/identity.json) or parent directory to .gitignore. If these are intended to be mock keys for testing, they should be relocated to a dedicated test fixtures directory and explicitly documented as non-production dummy keys. Note that any compromised keys that were ever used in a production or publicly accessible context must be considered burnt and immediately rotated.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@data/hub/identity.json` at line 1, Remove data/hub/identity.json from version
control and add its path or parent directory to .gitignore so generated identity
state is not committed. Treat the exposed signing_private and encryption_private
values as compromised and rotate them wherever they may have been used; only
retain replacement dummy keys in explicitly documented test fixtures if testing
requires them.

ProjectStore exposes get_project, not get. Both community_snapshot
and community_stats were calling project_store.get(project_id) which
would raise AttributeError at runtime. This was masked in CI by the
earlier task_store KeyError.

CodeRabbit CRITICAL finding fixed.

Docs-Reviewed: method-name correction only, no new structural changes

Refs: jaylfc#2042
hognek added a commit to hognek/tinyagentos that referenced this pull request Jul 19, 2026
ProjectStore exposes get_project, not get. Both community_snapshot
and community_stats were calling project_store.get(project_id) which
would raise AttributeError at runtime. This was masked in CI by the
earlier task_store KeyError.

CodeRabbit CRITICAL finding fixed.

Docs-Reviewed: method-name correction only, no new structural changes

Refs: jaylfc#2042
@jaylfc

jaylfc commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Deep review at head 2f74a30. CI is genuinely green and the earlier CodeRabbit critical (project_store.get AttributeError) is fixed, but this is a HOLD. Numbered folds, 1/5/6/7 are hard blockers:

  1. CRITICAL: data/hub/identity.json commits real private keys (signing_private + encryption_private, created 2026-07-19). This is runtime state from your local hub instance and has nothing to do with the community view. Note it is a repeat: your hub branch already hit this exact file and fixed it (500da60 added data/hub/ to .gitignore), but that gitignore only lives on the unmerged hub branch, so this PR reintroduces it as tracked. Required: rewrite the branch so the file never enters dev history (not just a delete commit), add data/hub/ to .gitignore in THIS PR, and treat both key pairs as burned - regenerate on your instance.
  2. Scope vs Collab F: collaborator community view (stats + leaderboard + live kanban + community chat) #2021: community chat is silently absent. Fine to slice it out, not fine to drop it silently - state the deferral in the PR body and do not close Collab F: collaborator community view (stats + leaderboard + live kanban + community chat) #2021 on merge.
  3. Peer serving missing: routes are owner-only (community.py:74-75, 138-139), so the actual audience (the remote collaborator) cannot reach the view. Acceptable as a slice but needs its own tracked follow-up issue before merge.
  4. Not live as shipped: CommunityView.tsx:125-145 fetches once on mount; the /community/stats endpoint built for polling is never called by any UI code. Wire polling or the SSE infra already in projects.ts, or descope 'live' explicitly.
  5. Auth pattern deviation: community.py returns a bare 403 with no admin bypass; every other project route uses if not user.is_admin and user.user_id != p["user_id"] with a masked 404 (projects.py:136, 294, 432, 1085). The 403 leaks project existence. Align with the house pattern.
  6. tests/test_community.py has no cross-user ownership test (the one security property these routes add), and the if len(body["leaderboard"]) > 0: guard at line 145 lets the leaderboard assertions pass vacuously. Both need fixing.
  7. ProjectWorkspace.tsx:108: mobileTabOrder is missing "community" - the tab is unreachable on mobile.
  8. No vitest for CommunityView; F3 scoped UI + tests and ProjectsApp has 15+ component test files as the norm.
  9. CommunityView.tsx:164-165: tasks with a status outside the hardcoded 5 vanish from the board but still count in Overview totals.
  10. Nit: the --pico-color-* vars in StatusBadge do not exist in the taOS design system, so the hex fallbacks always win and ignore theming - use --color-shell-* tokens like the rest of your new CSS.

Priority order: 1 first (key hygiene, branch rewrite), then 5/6/7, then the deferral notes (2/3) and 4/8/9/10.

hognek added a commit to hognek/tinyagentos that referenced this pull request Jul 20, 2026
…gerprint

jaylfc deep review at 4b5903b — fold all six findings:

1. BLOCKER: peer_fingerprint retrofit migration was a no-op on every
   pre-existing DB.  BaseStore's migration runner uses baseline-at-latest
   semantics — existing DBs get stamped at version 1 without executing
   the ALTER, so the column was absent after init().  The broad except in
   _try_handshake swallowed the resulting OperationalError, and the
   block-cascade security fix was similarly swallowed.

   Replaced the MIGRATIONS list with a guarded _post_init that checks
   PRAGMA table_info('contacts') and ALTER TABLE ADD COLUMN only when
   peer_fingerprint is absent.  Same pattern as agent_registry_store's
   _migration_v1_add_status.  Fresh databases still get the column from
   SCHEMA; upgraded databases get it from _post_init.

   Added two ContactsStore upgrade tests in test_store_upgrades.py
   following the existing pattern — column-presence check and
   add_contact-after-upgrade.

2. Fold 1 (send_handshake): A2 intentionally stores the inbound token
   locally without delivering it — the token exchange channel doesn't
   exist yet.  A3 completes the two-way exchange.  The send_handshake
   envelope builder from jaylfc#2046 is deferred to a follow-up PR linked from
   the tracking issue.  This is a spec deviation from
   cross-user-collaboration.md Day 0 (mint token on BOTH sides), filed
   as a tracking issue.

3. Fold 3 (.gitignore): the data/hub/ ignore line is justified — this
   branch's own history committed identity.json with throwaway test keys
   at 2b28043 (removed at 500da60).  The .gitignore prevents future
   accidental commits.  Squash merge will keep dev history clean.

4. Key hygiene: the keys in 2b28043 were throwaway test keys never used
   against real endpoints.  Squash merge removes them from dev history.
   jaylfc#2042 re-commits the same file; coordination note added in-thread.

5. Re-trigger: @coderabbitai review after push.

6. Track-don't-block (Kilo W1): accepted the documented NOTE about
   contact_id bound to peer-controllable username.  Follow-up issue filed
   for fingerprint-keyed contact IDs in a future slice.

BONUS: Fixed CodeRabbit nit from head review — test_accept_reupsert_contact
now actually revokes between accepts to verify re-establishment clears
revoked_at (was a no-op assertion before).
CRITICAL fixes:
- Scrub data/hub/identity.json from git history (private keys exposed)
- Add data/hub/ to .gitignore so runtime identity never lands again

Hard blockers:
- Auth pattern: bare 403 → masked 404 with admin bypass
  (community.py now uses  + 404, matching projects.py)
- Cross-user ownership tests: add two_member_clients fixture +
  snapshot + stats cross-user 404 tests (masked, no existence leak)
- Fix conditional assertion in test_community_stats: remove
  vacuous  guard, assert directly
- mobileTabOrder: add 'community' so tab is reachable on mobile

Quality:
- StatusBadge: replace nonexistent --pico-color-* CSS vars with
  --board-status-ready/claimed/closed + --color-traffic-close
  (the actual taOS design tokens)
- Kanban: include unknown statuses as extra columns so no task
  silently vanishes from board (was: only hardcoded 5)
- Live polling: CommunityView now polls /community/stats every 30 s
  for live leaderboard + status_counts update
- vitest: add 4 CommunityView component tests (loading, error,
  empty, populated render)

Deferred (per review findings 2/3):
- Community chat: scoped out of Milestone F; will land in
  a follow-up slice. Do not close jaylfc#2021 on merge.
- Peer-serving: route is owner-only for v1; tracked as follow-up.
  Collaborator auth will be wired once milestones A/B fully land.

Python tests: 10/10 pass.  vitest: 4/4 pass.  SPA build: clean.
@hognek
hognek force-pushed the feat/collab-f-community-view branch from 2f74a30 to f71bbc7 Compare July 20, 2026 16:56
project = await project_store.get_project(project_id)
if project is None:
raise HTTPException(status_code=404, detail="project not found")
if not user.is_admin and project.get("user_id") != user.user_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Admin bypass grants any admin read access to every user's community projection.

if not user.is_admin and project.get("user_id") != user.user_id lets any admin read the full task board, contributor leaderboard, and activity feed for projects they don't own. This mirrors the existing projects.py owner/admin pattern, so it's consistent with the app's model — but the Community View is explicitly scoped as a privacy-sensitive projection meant for the owner plus delegated peer-token contacts. Every admin now silently gets cross-user read access to this data with no audit/visibility.

Consider whether admin access is actually required here. If it is only needed for support/debugging, gate it behind an explicit capability or at least log the cross-user access (as add_member already does for human overrides). If it's not needed, drop the not user.is_admin clause so the view is owner-scoped like the feature description implies.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@jaylfc

jaylfc commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Checking in on this one. The fold list has been open for about 24 hours with no response, and item 1 is a security finding rather than a style point, so I do not want it to drift.

The blocking item remains: data/hub/identity.json commits real signing and encryption private keys. Treat those as burned and regenerate regardless of what happens to this PR. The fix needs the file gone from the branch history (not just deleted in a later commit) and data/hub/ added to .gitignore here, since the ignore currently only exists on your unmerged hub branch.

The rest of the list stands: owner-only routes mean the actual audience (a remote collaborator) cannot reach the view, the bare 403 leaks project existence where the house pattern uses an admin bypass and a masked 404, and mobileTabOrder is missing "community" so the tab is unreachable on phones.

Flagging priority honestly: Jay asked today where the contributor project view stands, and the answer is that it is this PR. So it is wanted, not parked. If the branch-history rewrite is the awkward part, say so and we can talk about landing it as a fresh branch instead, which may genuinely be less work than rewriting history.

Also relevant to you: taosmd's maintainer documented their response envelopes and built a /version capabilities endpoint after we asked. Their repo (jaylfc/taosmd) is public with issues enabled, so for future contract questions you can open an issue there directly rather than routing through me. I am confirming with them that they watch it; until then, ask on the PR and I will carry it.

@jaylfc

jaylfc commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Separate from the fold list: you have a pending collaborator invite on jaylfc/taos-agent-commons that has not been accepted yet. Worth accepting, because it is about to become your direct line to the other teams' agents rather than everything routing through me by hand.

The problem it solves is the one that cost this PR two rounds. taOSmd's contract questions were answerable in one message, but you had no way to ask its maintainer, so you inferred from what looked reasonable and I only caught it in review. That is a process failure, not a you failure.

How it will work:

  • Open an issue on taos-agent-commons, label it contract-question, name the service (taosmd, website).
  • I sweep that repo hourly and relay to the owning agent on the A2A bus, then bring the answer back to you.
  • jaylfc/taosmd is public with issues enabled, so taosmd questions can also go straight there if you prefer a direct thread.
  • jaylfc/taos-website is private, so commons or me is the only route for that one.
  • If something sits unanswered more than a couple of hours, raise it on the PR too. The relay runs through my session, and my session has died before today. Do not let silence look like progress.

This is deliberately temporary scaffolding. It goes away when an external contributor can hold a taOS identity and reach the bus directly, which is a feature Jay wants to build with you as the first real test.

Documented in the taOS development skill so it is not just this comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants