Keep the personal half of the desktop in one place, and ask before installing it
Agent instructions, skills, SSH host aliases and expansion triggers are worth having identical on every machine one person owns, and belong in none of the shared configuration. They live in user/ now, with a manifest saying where each piece goes and a link-user stage that puts it there. That stage does nothing unless the machine said yes. Somebody who clones Panama to try the desktop keeps their own ~/.claude/CLAUDE.md exactly where it was; the question names the destinations and defaults to no. Anything displaced goes to config/old rather than being deleted. ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md were byte-identical copies of one file, which is the drift this exists to prevent. Also adds the vitals toggles for the battery and Claude usage readouts, which had preferences and no way to reach them.
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# Estimation method
|
||||
|
||||
The estimate is engineering hours for the story's scope as written. It excludes buffer: the Story Risk Level is what communicates uncertainty buffer, per the dev review SOP. Never conflate the two, a large story can be LOW risk (lots of pattern following work) and a small story can be MEDIUM or HIGH (novel modeling in few files).
|
||||
|
||||
## The method, in order
|
||||
|
||||
1. Build the Code paths and intended updates table first. The estimate is derived from it, never invented independently of it.
|
||||
2. Assign hours per row or per cluster of rows using the anchor table below, at 0.25 hour granularity. Include test files in the rows they verify.
|
||||
3. Sum and round up to the nearest 0.5 hour.
|
||||
4. Sanity check the total against the nearest anchor story below. If the total differs from the anchor by more than about a third, either the scope read is wrong or the anchor does not fit, figure out which and say so in the Estimate subsection.
|
||||
5. Apply the bands:
|
||||
- Bugs and small tasks default to 2 hours, 1 hour when genuinely trivial.
|
||||
- Stories normally land between 2 and 8 hours. 8 hours is the practical upper bound for a single ticket.
|
||||
- A total above 8 hours is a solid argument the ticket should be more than one ticket: the review must say so and sketch the split.
|
||||
- 10 hours is a hard cap. The skill never sets an Original Estimate above 10 hours, ever. A story that computes above 10 gets no estimate set until the split question is resolved with the user.
|
||||
6. Show the work: the review's Estimate subsection carries the breakdown table (work item, hours) and ends with "Recommended Jira original estimate: N engineering hours."
|
||||
7. Calibrate down, not up (Gib, 2026-08-14). The estimates assume Gib develops with agent assistance, so pattern following surfaces, cards, column definitions, copy sweeps, and test files go faster than a solo dev baseline. Lean toward the low end of every band. Across an epic the distribution matters: most stories should land 2 to 6 hours, and a wall of 8 plus estimates reads like gaming the system to the people approving them. Reserve 8 and above for genuinely large compositions, and when a total creeps high, first re-check the scope read for anything that actually belongs to a neighboring story.
|
||||
|
||||
## Anchor table, calibrated from real Command Center estimates
|
||||
|
||||
From 100 estimated KACP issues on the Ksense Command Center account (53 bugs median 2h, 24 tasks median 2h, 23 stories median 5h), with named anchors:
|
||||
|
||||
| Work shape | Hours | Anchors |
|
||||
| --- | --- | --- |
|
||||
| Trivial fix, styling pass, config change | 1 to 2 | KACP-22843 styling 1h, KACP-22868 tutorials fix 2h |
|
||||
| Bug fix on an existing surface | 2 | The overwhelming KCC default, 2h across dozens of bugs |
|
||||
| Small workflow or logic tuneup | 3 | KACP-22201 interest holder workflow tuneup 3h |
|
||||
| Notification or email story on existing plumbing | 3.5 | KACP-22194, KACP-22195 notifications 3.5h each |
|
||||
| Modal or single form on existing patterns | 4 to 5 | KACP-22197 logs modal 4.5h |
|
||||
| Additive schema plus seed, no backfill | 3.5 to 5 | KACP-22200 cron sync tables 5h |
|
||||
| Grid rework or tuneup on the existing DataGrid | 5 | KACP-22196 epic grid tuneup 5h |
|
||||
| New grid page on existing patterns | 6 to 8 | Portal grid reviews ran 6h (KACP-23136) to 10h (KACP-22814), KCC side stays in band |
|
||||
| Detail page with cards or tabs on existing patterns | 5 to 7 | KACP-22882 signature logging and data model 7h |
|
||||
| New end to end surface, UI plus API plus side effects | 6.5 to 8 | KACP-22888 e-sign email 6.5h, KACP-22885 certificate 7.5h |
|
||||
| Schema with production backfill or migration review queue | Add 2 to 3 to the schema base | This is the most common reason a story crosses 8 and should split |
|
||||
|
||||
Historical over the line examples for the split argument: KACP-22881 at 9.5h, KACP-23006 at 14h, KACP-20762 at 17h. Under the current rule each of those gets a split recommendation in its review instead of a large estimate.
|
||||
|
||||
## Per row guidance
|
||||
|
||||
- A focused test file rides with its surface at 0.5 to 1 hour, not as a separate large line.
|
||||
- LaunchDarkly flag plumbing on a surface is 0.5.
|
||||
- Seed catalog entries are 0.5 to 1.
|
||||
- Route or page shell with nav and guard is 1 to 2 on its own, and folds into the page's line when the story includes the page.
|
||||
@@ -0,0 +1,160 @@
|
||||
# Reference example: KACP-22813 Firm - Routes and page (dev review, verbatim)
|
||||
|
||||
This is a real Developer Review Instructions field from a reviewed story, rendered to markdown. It is the calibration target for structure, depth, and voice. Note it comes from the APSCA portal repo, so its file paths and stack idioms are that repo's, only the anatomy is the standard.
|
||||
|
||||
## 1. Objective
|
||||
|
||||
Add the Firm Team page shell at `/firm/team` by reusing the established full-width Firm Tasks page composition. Register Team in the Firm navigation and apply the existing Firm Membership CASL permission consistently to both the menu item and direct route access.
|
||||
|
||||
## 2. Current State
|
||||
|
||||
- The Firm portal layout already authenticates the user, resolves their Firm Membership, renders the Firm sidebar, and protects the Firm portal as a whole.
|
||||
- `src/app/[locale]/firm/tasks/layout.tsx` already demonstrates the Firm data-grid page composition: a shared `PageHeader` followed by `MainContent` using `layoutWidth="dataGrid"`.
|
||||
- `src/app/[locale]/firm/tasks/page.tsx` provides the established responsive `Stack` and full-width `Box` layout for a Firm table or grid.
|
||||
- `src/app/[locale]/firm/tasks/_components/tasks-header.tsx` provides the closest Firm header implementation using the shared `PageHeader`.
|
||||
- `getFirmMenuConfig()` already registers Firm Management menu items. `createSidebarMenu()` applies CASL to each configured `subject` and renders denied items in the existing locked state.
|
||||
- `firmPortal.can()` already exposes a server-side permission check without requiring page code to inspect Firm roles.
|
||||
- No `/firm/team` route or Team menu item currently exists.
|
||||
- The currently implemented `FirmMembership` read rule permits every Firm portal membership. The role-aware Firm Administrator, Team Member, and Contact rules are owned by the intended review for Database, CASL policies, etc. (KACP-22817) and must be available for the required access behavior to work.
|
||||
|
||||
## 3. Desired State
|
||||
|
||||
The Firm sidebar displays Team under Firm Management.
|
||||
|
||||
- Firm Administrators and Team Members receive an enabled Team menu item and can open `/firm/team`.
|
||||
- Contacts see the Team menu item in the existing locked state.
|
||||
- A Contact who enters `/firm/team` directly is redirected to the localized Firm dashboard.
|
||||
|
||||
The page follows the existing portal presentation:
|
||||
|
||||
- A shared Firm page header displays the title **Team** and subtitle **Manage who can access your account and who APSCA contacts.**
|
||||
- The content uses the same data-grid width as Firm Tasks.
|
||||
- One full-width Team content surface provides the insertion point for the grid delivered by Firm - Team Members Grid (KACP-22814).
|
||||
|
||||
The menu and page use the same `read`, `FirmMembership` CASL capability. The page does not inspect roles or duplicate authorization policy.
|
||||
|
||||
## 4. Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- Add the `/firm/team` server page.
|
||||
- Add the Team page header using the shared `PageHeader` and the Firm Tasks header pattern.
|
||||
- Compose the page with `MainContent`, `Stack`, and `Box` using the existing data-grid width layout.
|
||||
- Add Team under Firm Management in the Firm menu configuration.
|
||||
- Use `FirmMembership` as the menu item's CASL subject.
|
||||
- Check the same Firm Membership read capability in the page before rendering.
|
||||
- Redirect denied direct-route access to the localized Firm dashboard.
|
||||
- Add focused route and navigation authorization coverage.
|
||||
|
||||
### Developer acceptance criteria
|
||||
|
||||
1. The Team page remains a server component and resolves authorization before rendering protected content.
|
||||
2. The page uses `firmPortal.can('read', 'FirmMembership')`; it does not import the CASL engine or inspect `FirmContactRole`.
|
||||
3. The menu item and route guard both use the `FirmMembership` subject, preventing navigation and direct access from drifting apart.
|
||||
4. A denied direct request redirects through `localePath('/firm/', locale)` so the current locale is preserved.
|
||||
5. Firm portal authentication and Firm Membership resolution remain owned by the existing Firm layout.
|
||||
6. The Team content uses `layoutWidth="dataGrid"` and a full-width `Box` with `flex: 1` and `minWidth: 0`, matching Firm Tasks.
|
||||
7. The header uses the shared `PageHeader` with the same data-grid width, preserving its semantic heading markup and responsive spacing.
|
||||
8. The page shell introduces no grid query, client state, mutation, or role-specific rendering.
|
||||
9. Focused tests demonstrate the allowed page render, denied redirect, enabled authorized menu item, and locked unauthorized menu item.
|
||||
10. Verification uses the role-aware CASL policy from KACP-22817 to confirm Firm Administrator and Team Member access and Contact denial.
|
||||
|
||||
### Explicitly out of scope
|
||||
|
||||
- Team grid rows, columns, data loading, empty states, pagination, search, sorting, or filtering.
|
||||
- Add Person, Edit Person, View Person, or any other Team interaction.
|
||||
- Add or edit controls.
|
||||
- Prisma schema or migration changes.
|
||||
- Defining or duplicating the Firm Administrator, Team Member, or Contact CASL rules owned by KACP-22817.
|
||||
- Firm Membership commands or mutations.
|
||||
- Clerk identity or invitation behavior.
|
||||
- Communications, templates, or notification behavior.
|
||||
|
||||
### Estimate
|
||||
|
||||
| Work | Hours |
|
||||
| --- | --- |
|
||||
| Team route, header, and data-grid-width page shell | 0.75 |
|
||||
| Firm menu item, CASL route check, and localized redirect | 0.5 |
|
||||
| Focused tests and verification | 0.75 |
|
||||
| **Total** | **2** |
|
||||
|
||||
Recommended Jira original estimate: **2 engineering hours**.
|
||||
|
||||
## 5. Suggested Implementation
|
||||
|
||||
### Code paths and intended updates
|
||||
|
||||
| Code path | Brief intended update |
|
||||
| --- | --- |
|
||||
| `src/app/[locale]/firm/team/page.tsx` | Add the server page. Resolve `params` and `firmPortal.can('read', 'FirmMembership')`, redirect denied users to the localized Firm dashboard, and compose the Team header plus the data-grid-width `MainContent`, responsive `Stack`, and full-width `Box` used by Firm Tasks. Reserve the content surface for the later grid story. |
|
||||
| `src/app/[locale]/firm/team/_components/team-header.tsx` | Copy the small Firm Tasks header wrapper, rename it for Team, and render the required title and subtitle through the shared `PageHeader` with `layoutWidth="dataGrid"`. Do not introduce a new generic header abstraction. |
|
||||
| `src/app/[locale]/firm/_components/menu-config.tsx` | Add Team under Firm Management, linking to the localized `/firm/team/` route, using the existing `Users` icon and `subject: 'FirmMembership'` so the shared menu authorization renders the locked Contact state. |
|
||||
| `src/app/[locale]/firm/team/page.test.tsx` | Add focused server-page coverage for authorized rendering and denied localized redirect. |
|
||||
| `src/app/[locale]/firm/_components/menu-config.test.tsx` | Confirm the Team item is registered under Firm Management and that the shared authorization transform enables it when `FirmMembership` read is allowed and locks it when denied. Do not test role names in the menu configuration. |
|
||||
|
||||
The intended server-page authorization shape is:
|
||||
|
||||
```tsx
|
||||
const [{ locale }, canViewTeam] = await Promise.all([
|
||||
params,
|
||||
firmPortal.can('read', 'FirmMembership'),
|
||||
]);
|
||||
|
||||
if (!canViewTeam) {
|
||||
redirect(localePath('/firm/', locale));
|
||||
}
|
||||
```
|
||||
|
||||
The page should then follow the established composition:
|
||||
|
||||
```tsx
|
||||
<>
|
||||
<TeamHeader />
|
||||
<MainContent
|
||||
layoutWidth="dataGrid"
|
||||
sx={{ py: 3, pb: 8 }}
|
||||
>
|
||||
<Stack
|
||||
direction={{ md: 'column', lg: 'row' }}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
<Box sx={{ flex: 1, minWidth: 0, width: '100%' }}>
|
||||
{/* KACP-22814 supplies the Team grid. */}
|
||||
</Box>
|
||||
</Stack>
|
||||
</MainContent>
|
||||
</>
|
||||
```
|
||||
|
||||
Do not add a client-side role check, new portal service, or grid read model. The shared `PageHeader`, `MainContent`, Firm Portal façade, and menu authorization already provide the required seams.
|
||||
|
||||
## 6. Happy Path
|
||||
|
||||
1. An authenticated Firm Administrator or Team Member opens the Firm portal.
|
||||
2. The Firm layout resolves their current Firm Membership and builds the Firm CASL ability.
|
||||
3. The sidebar applies that ability to the Team menu item's `FirmMembership` subject and renders the item as enabled.
|
||||
4. The user opens Team and reaches the localized `/firm/team` route.
|
||||
5. The server page checks the same Firm Membership read capability.
|
||||
6. The page renders the Team header and full-width data-grid layout.
|
||||
7. The Team content surface is ready for KACP-22814 to supply the grid without changing the route, header, navigation, width, or authorization composition.
|
||||
|
||||
## 7. Edge Cases to Consider
|
||||
|
||||
### Provided
|
||||
|
||||
- A Team Member can view the Team page but cannot edit it.
|
||||
- A Contact sees the Team menu item in a locked state.
|
||||
- A Contact who enters the route directly is redirected to the Firm dashboard.
|
||||
- Grid content and interactions belong to a separate story.
|
||||
|
||||
### Added during dev review
|
||||
|
||||
- The route must preserve the current locale when redirecting a denied user.
|
||||
- A user without a valid Firm Membership remains rejected by the existing Firm layout before the Team page is rendered.
|
||||
- The menu and direct route must not use different CASL subjects or independent role checks.
|
||||
- KACP-22817 must replace the current broad Firm Membership read grant before Contact denial can be verified correctly.
|
||||
- The header and main content must both use the data-grid width so their horizontal alignment remains consistent.
|
||||
- The table/grid wrapper must retain `minWidth: 0` and `width: '100%'` so wide content does not break the portal layout.
|
||||
- The empty shell must not invent temporary grid data, controls, or client state that KACP-22814 would later remove.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# SOP for Development Review (KACP-23147, verbatim duties)
|
||||
|
||||
Developer Review Instructions. SOP for Development Review:
|
||||
|
||||
1. **Review the Epic.** Review the issues in this epic to ensure you understand what the requirements are. Reach out to the PM for clarification if needed.
|
||||
2. **Handle Sprint Flag.** Assess whether a flag is needed for this Sprint, create it, and connect it to the Epic. Create the flag in LaunchDarkly (if applicable) and connect it to the Epic in the Releases field.
|
||||
3. **Add development instructions.** For each issue in the epic, add development instructions using the Developer Review Instructions field. Follow the Developer Instructions template to provide clear, concise, and actionable guidance for the development team. Focus on providing context and information not already outlined in the task details to avoid redundancy.
|
||||
4. **Add issue dependencies.** Identify and link dependent issues within the epic using the Blocks or is blocked by link type. Ensure that the issue dependencies are accurately represented to facilitate proper planning and execution.
|
||||
5. **Provide time estimates.** Fill out the Original Estimate field for each issue in the epic. Provide your best estimate of how long each issue will take to complete, considering factors such as complexity, dependencies, and potential risks.
|
||||
6. **Fill out the Risk Level.** Choose the appropriate Story Risk Level for each task in the epic. The Risk Level adds a buffer to the original estimate based on the task complexity, accounting for potential unknowns or challenges.
|
||||
7. **Fill out the Testing Tab.** Based on the Technical Review and your assessment of the risks associated with each task, fill out the Risk Mitigation and Test Cases tables.
|
||||
- Risk Mitigation: identify and list the risks associated with each task. Specify the mitigation strategy for each risk, which could include guidance on how to build the feature in a way that mitigates the risk, or outlining automated tests that need to be created to address the risk. If an automated test is required, create a subtask on the main task with the type of test and what it covers, and an estimate for the subtask.
|
||||
- Test Cases: outline the manual test cases that the developer should execute to ensure the functionality works as expected and risks have been addressed.
|
||||
8. Close this issue when finished.
|
||||
Reference in New Issue
Block a user