Sloth-ninja gives firms a real library with real boundaries

JessicaOSS is adding firm-wide knowledge sharing without treating every colleague as entitled to every document.

knowledge-managementsecurity

The fork adds a firm library, a people-management view and clear visibility badges, so teams can see which material is personal and which belongs to the wider firm.

  • Firm library: a shared place for material intended for the organisation.
  • People controls: a way to manage who can see firm-level content.
  • Visibility badges: clearer signals about a document's audience.
  • Deletion safeguards: access is also blocked when a parent item has been deleted, closing a route to content that should no longer be available.

This is a joined-up access model, not merely a new interface, and it requires the supporting database change and server-side checks to be active.

So what Firms building a reusable internal knowledge base should care because sharing becomes more practical without weakening deletion and access controls.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

13 commits from Sloth-ninja/JessicaOSS, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
a5da048f WS9 PR 1: firm-visibility migration + spec sloth-ninja 2026-07-28 ↗ GitHub
commit body
Owner-authorised 28/07/2026 (allowlist entry added by the owner).
projects.organisation_id (dead visibility column becomes live:
private|firm); tabular_reviews gains visibility + organisation_id;
partial firm-visible indexes; deletion_audit_logs action check extends
with firm_shared/firm_reverted; both overview functions recreated with
p_user_org_id (old signatures dropped) + firm predicate + visibility in
returns. No behaviour change until a caller passes the org id (PR 2).
Spec: docs/FIRM_LIBRARY_SPEC.md; approved mock-ups linked in BUILD_LOG.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
47bf2e90 Merge pull request #54 from Sloth-ninja/ws9-firm-visibility-migration Ezana.H 2026-07-28 ↗ GitHub
WS9 PR 1: firm-visibility migration + spec
2cc393d1 WS9 PR 2: firm-visibility backend (access branches, visibility routes, firm library) sloth-ninja 2026-07-28 ↗ GitHub
commit body
Enforce and expose the firm library on top of migration 20260728_02:

- lib/access.ts: firm branch added to checkProjectAccess, ensureReviewAccess,
  ensureDocAccess, listAccessibleProjectIds, filterAccessibleDocumentIds - an
  item is accessible when visibility='firm' AND organisation_id = the caller's
  org (resolved once via getUserOrganisationId, threadable, 42703-tolerant).
  Firm viewers are non-owners; project-scoped reviews inherit their matter's
  visibility; missing columns => firm branch silently absent (legacy fallback).
- projects/tabular overview RPC calls pass p_user_org_id; GET /projects/:id and
  /people route access through checkProjectAccess so firm viewers reach matters.
- lib/firmVisibility.ts (self-contained seam): owner flip (predicate-encoded,
  owner-only), admin revert (org-scoped cross-org exclusion), firm-library list
  (reuses the overview RPCs filtered to visibility='firm').
- Routes: PATCH /projects/:id/visibility, PATCH /tabular-review/:id/visibility
  (owner-only, orgless 403, project-scoped review rejected 400), admin
  GET /admin/firm-library + POST /admin/firm-library/:type/:id/revert (MFA),
  member GET /firm-library, GET /user/firm-members (displayName+email only).
  All flips best-effort audited firm_shared/firm_reverted.

Tests: 500 passed (442 baseline + 58 new: access matrix, firmVisibility predicate
atomicity + cross-org, and the four route suites). tsc clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
aed5f1d6 Merge pull request #55 from Sloth-ninja/ws9-firm-visibility-backend Ezana.H 2026-07-28 ↗ GitHub
WS9 PR 2: firm-visibility backend (access branches, visibility routes, firm library)
913897ac WS9 PR 3: firm-visibility frontend (PeopleModal, Firm library, badges) sloth-ninja 2026-07-28 ↗ GitHub
commit body
Build the firm-library UI on top of WS9 PR 2's backend (#55). Frontend only;
no backend/migration/.env touched. Built to the approved mock-ups.

- mikeApi: getFirmMemberSuggestions, updateProjectVisibility,
  updateTabularReviewVisibility, getFirmLibrary, getAdminFirmLibrary,
  revertFirmLibraryItem; visibility field on the Project/TabularReview types.
- PeopleModal: firm-member suggestion pills (owner + firm only; external
  emails still free-typed) and a "Visible to everyone at <firm>" toggle
  (owner-only, optimistic + rollback, confirm-before-ON, audit info strip);
  project-scoped reviews show an inherited-visibility note instead of the
  toggle. AccountToggle gains an ariaLabel prop.
- Firm library page ((pages)/firm-library) + a firm-gated sidebar item.
- Admin Firm settings: a "Firm library" card with MFA-guarded per-item
  Revert to private (confirm + optimistic removal + rollback).
- FirmBadge (indigo pill) on firm-visible rows in the matters and
  tabular-reviews lists, via a new TablePrimaryCell adornment prop.

Deviations (honesty-driven, noted in BUILD_LOG): admin card shows "updated"
not "firm-visible since" (payload has only updatedAt); review rows show
document count without a column count (not in the firm-library payload).

Verification: frontend tsc clean; eslint introduces zero new problems (3
pre-existing set-state-in-effect errors on untouched lines). No prettier on
frontend files. Backend tsc + vitest re-run green (500/500) to prove it was
untouched. Screenshots pending (headless worktree; mock-ups are the reference).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c59adce3 Merge pull request #56 from Sloth-ninja/ws9-firm-visibility-frontend Ezana.H 2026-07-28 ↗ GitHub
WS9 PR 3: firm-visibility frontend (Firm library, PeopleModal, badges)
cee6bc61 WS9 fix wave: compose firm-visibility with deletion governance (WS8×WS9) sloth-ninja 2026-07-28 ↗ GitHub
commit body
Composed-range re-review of the WS9 train surfaced five fixes, all in the
WS8×WS9 interaction class (firm visibility reads through rows deletion
governance tombstones; the two seams were never composed):

1. Parent-tombstone gap (important): tombstoning sets only deleted_at, so a
   tombstoned firm-visible matter/review still passed checkProjectAccess /
   ensureReviewAccess, and the content sub-routes (never re-checking the
   tombstone) let any firm member read - and via /generate, /chat WRITE - a
   soft-deleted item for the whole retention window. Folded the tombstone
   check into both helpers (choke point): tombstoned parent => not-ok for
   everyone incl. the owner. 42703-tolerant. Detail-route guards left as
   defence-in-depth. Restore/expedite/list paths verified unaffected.
2. setResourceVisibility now refuses a tombstoned item (.is deleted_at null
   in the predicate => not_found).
3. Audit resource_type unified to hyphenated "tabular-review" for both firm
   actions (flip route + admin revert param mapping); URL/API keep underscore.
4. PeopleModal add-member placeholder gains firm copy when firm surfaces show.
5. Firm-library rows: role=button + tabIndex + Enter/Space + aria-label.

Tests: +11 (backend 511/511). tsc/eslint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
d21d6d7a Review fix: parent-tombstone gate in ensureDocAccess owner path; tr role=link sloth-ninja 2026-07-28 ↗ GitHub
commit body
Independent review of PR #57 (REQUEST_CHANGES, one should-fix):

- ensureDocAccess returned {ok:true} for the document owner BEFORE reaching
  checkProjectAccess, so the folded-in parent-tombstone gate only fired on the
  non-owner path. A doc owner (or a firm colleague who uploaded a doc into
  someone else's tombstoned firm matter) could still GET/download it for the
  retention window. Added the parent-matter tombstone check before the owner
  short-circuit (mirrors ensureReviewAccess); standalone docs (project_id null)
  unaffected. 42703-tolerant. +2 tests.

- NIT: firm-library <tr> role="button" -> role="link" (navigation semantics;
  keeps tabIndex/handlers/focus style).

Backend 513/513, tsc clean. Frontend tsc/eslint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
e3c82310 Merge pull request #57 from Sloth-ninja/ws9-train-fixes Ezana.H 2026-07-28 ↗ GitHub
WS9 fix wave: compose firm-visibility with deletion governance (WS8×WS9)
d0071663 WS9 close-out: status refresh + cwd-drift durable lesson sloth-ninja 2026-07-28 ↗ GitHub
commit body
CLAUDE.md Current status: WS9 complete (#54-#57) and deployed; 20260728_01
run in prod (saves active); 20260728_02 owner-pending; Quill re-registration
state. DURABLE_LESSONS: shell cwd drift into a worktree silently updated the
wrong refs and invalidated a composed-range review - git -C absolute paths
for ref-affecting commands, SHA-pinned review ranges.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
71bf18bd Merge pull request #58 from Sloth-ninja/ws9-closeout Ezana.H 2026-07-28 ↗ GitHub
WS9 close-out: status refresh + cwd-drift durable lesson
6c0eee88 Status: 20260728_02 run in production - WS9 firm library active sloth-ninja 2026-08-03 ↗ GitHub
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
319969ff Merge pull request #60 from Sloth-ninja/ws9-activation-note Ezana.H 2026-08-03 ↗ GitHub
Status: WS9 firm library active in production

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-1002.md from inside the repo you want the changes in.

⬇ Download capture-thread-1002.md