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 |