Commit graph

553 commits

Author SHA1 Message Date
1f5a65ecc1 docs(phase-14): update tracking after wave 4 2026-07-11 15:09:40 -04:00
a6f5ca39a3 docs(14-06): record human verification checkpoint approval 2026-07-11 15:09:40 -04:00
3bf0244648 docs(phase-14): update tracking after wave 3 2026-07-11 14:46:09 -04:00
3951298da2 chore: merge executor worktree (worktree-agent-a08db5af4833dc6c9) 2026-07-11 14:45:17 -04:00
e80a816ec6 docs(14-05): record plan 05 execution summary
Needs Review tab (review cards, candidate resolve, manual-search
combobox, count badge) + companies-list requireAuth hardening.
2026-07-11 14:44:57 -04:00
13272f9a6f feat(14-05): manual company-search combobox fallback (D-05/D-09)
- Every review card gets a Command/Popover combobox fed by
  /api/data/companies-list, fetched once via ensureCompaniesLoaded()
  and shared across cards
- Selecting a company enables a "Link to selected company" button that
  calls the same resolve() handler as the candidate buttons
- Zero-candidate reviews (D-09) show only the manual picker; reviews
  with candidates show both candidate buttons and the manual picker
2026-07-11 14:43:56 -04:00
40efa1d3b6 feat(14-05): Needs Review tab review cards, candidate resolve, count badge
- Amber-bordered cards (border-amber-200) list unresolved PAX8 company
  match reviews, fetched from /api/pax8/company-matches on first tab
  activation
- Each candidate row offers a "Link company" button that POSTs to
  .../[id]/resolve; on success the card is optimistically removed,
  toast.success fires, and reviewTotal decrements
- Needs Review TabsTrigger shows a count badge when reviewTotal > 0
- Error/loading/empty states mirror device-link-conflicts' Alert/
  Skeleton/empty-state trio per UI-SPEC copy
- Zero-candidate reviews render the D-09 "No suggested matches" empty
  state; manual-search combobox insertion point left for Task 3
2026-07-11 14:43:05 -04:00
564be52b97 feat(14-05): harden companies-list route with requireAuth
- companies-list now feeds the manual-search fallback for authenticated
  UI (Needs Review tab), closes previously-unauthenticated gap
- response shape unchanged: [{ id, company_name }]
2026-07-11 14:42:10 -04:00
e9d5846cc8 docs(phase-14): update tracking after wave 2 2026-07-11 14:39:01 -04:00
30d8c9d46f chore: merge executor worktree (worktree-agent-a91f4d8cb6bd9f301) 2026-07-11 14:38:08 -04:00
a6ad8d504d docs(14-04): append self-check results to summary
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-11 14:37:50 -04:00
9b6faa95a1 docs(14-04): record plan completion summary
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-11 14:37:37 -04:00
543ac39d83 feat(14-04): add top-level PAX8 nav entry
- New top-level navigationItems entry (href: /pax8, icon: ShoppingCart)
- Not added to the Engagement/Admin visibleItems super-admin gate — visible to all authenticated users on both desktop NavigationMenu and mobile Sheet (D-07)
2026-07-11 14:36:52 -04:00
51470f8892 feat(14-04): /pax8 page shell + Companies tab (DataTable + DetailModal drill-down)
- New app/pax8/page.tsx client page with PageHeader + Companies/Needs Review Tabs shell
- Companies tab: DataTable of PAX8 companies (name, matched Autotask company or Unmatched badge, active subscription count, city/state/country) with sort/search/pagination against /api/pax8/companies
- Row click fetch-then-opens the extended DetailModal (kind="pax8_company") with subscriptions + cost breakdown from /api/pax8/companies/[id]
- Needs Review tab left as a marked placeholder for Plan 14-05
2026-07-11 14:36:31 -04:00
8e1114aeec docs(phase-14): update tracking after wave 1 2026-07-11 14:33:19 -04:00
8ce2d3fc9b chore: merge executor worktree (worktree-agent-a77f9b3a365cc0b6d) 2026-07-11 14:31:20 -04:00
580e7ac508 chore: merge executor worktree (worktree-agent-a11c767c2a8721d5b) 2026-07-11 14:31:20 -04:00
57db03b9ca chore: merge executor worktree (worktree-agent-a7f5ed0d03f07bb8a) 2026-07-11 14:31:20 -04:00
65acbe1adf docs(14-02): append self-check result to summary
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 14:30:31 -04:00
8306caf04d docs(14-02): add plan summary
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 14:30:18 -04:00
4d7a58b46c docs(14-02): drop literal candidate_company_ids mention from resolver docstring
Satisfies the plan's grep-based acceptance check for "no reference to
candidate_company_ids in the resolver source" — code already had no
membership check, this only reworded the explanatory comment.
2026-07-11 14:29:43 -04:00
a6dcc9e29e docs(14-03): record DetailModal PAX8 extension summary
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 14:29:26 -04:00
d61acf9ca5 docs(14-01): append self-check results to SUMMARY.md 2026-07-11 14:29:13 -04:00
a81e358be7 feat(14-02): add POST /api/pax8/company-matches/[id]/resolve route
- requirePermission('admin','access')-gated (D-08) — the write side of the
  asymmetric read/write auth split
- zod-validated body (companyId positive int, note <=500 chars)
- Delegates the two-table write to resolvePax8CompanyMatch inside
  postgresClient.transaction(); maps ResolveResult codes to HTTP status
  (ok->200, not_found->404, already_resolved->409, company_not_found->400)
2026-07-11 14:29:07 -04:00
501c7e4106 docs(14-01): complete PAX8 companies API routes plan
- Add SUMMARY.md documenting the two routes, deviations, and next-phase readiness
2026-07-11 14:28:58 -04:00
0ce51a0167 feat(14-02): implement resolvePax8CompanyMatch resolver
- Two-table transactional write: pax8_companies.match_method='manual' AND
  pax8_company_match_review.resolved_* in one call, so the matcher's
  re-scoring guard (pax8-company-matcher.ts ~216-231) never re-flags a
  manually resolved company
- Guards not_found / already_resolved via FOR UPDATE select
- Validates target company existence + active state (substitute for
  candidate-membership check — D-05/D-09 allow non-candidate ids)
- All five vitest behavior cases green; tsc clean
2026-07-11 14:28:48 -04:00
04c75bedf8 feat(14-03): render subscriptions cost-breakdown table in Formatted tab
- New section guarded by Array.isArray(data.subscriptions), rendered as
  the first child so it appears above field groups (UI-SPEC focal point)
- Product label falls back productName -> sku -> 'Unknown item'
- Amounts use latestBilledAmount directly (never unit_price * quantity),
  rendered font-mono tabular-nums, plus a summed total row
- Empty array shows a muted "No subscriptions" state instead of crashing
- Raw tab and existing ticket Description block unchanged
2026-07-11 14:28:45 -04:00
afdcf1412d test(14-02): add failing test for resolvePax8CompanyMatch
- Five behavior cases: success (both writes), not_found, already_resolved,
  company_not_found, and non-candidate companyId still resolves (D-05/D-09)
- Hand-rolled mock tx asserts SQL + bound params per query call
2026-07-11 14:28:44 -04:00
3492a16176 feat(14-03): add kind prop + PAX8_COMPANY_GROUPS to DetailModal
- Add optional kind?: 'ticket' | 'company' | 'pax8_company' prop to DetailModalProps
- Add PAX8_COMPANY_GROUPS field-group set (Identity + System, camelCase keys)
- detectGroups() checks kind === 'pax8_company' first, before existing sniff branches
- TICKET_GROUPS/COMPANY_GROUPS and their detection branches unchanged
2026-07-11 14:28:15 -04:00
2cc1abbf9a feat(14-01): add PAX8 company drill-down route with cost breakdown
- GET /api/pax8/companies/[id] with requireAuth gate (D-07), UUID validation, 404 on missing
- Per-subscription latest-billed cost via DISTINCT ON windowed query (Pitfall 2)
- Uses line_total not unit_price*quantity (Pitfall 3); fallback label chain (Pitfall 4)
- Surfaces tombstoned-subscription order-item rows with no matching subscription
2026-07-11 14:28:14 -04:00
443b6ce75b feat(14-01): add paginated PAX8 companies list route
- GET /api/pax8/companies with requireAuth gate (D-07)
- Whitelisted sort columns, parameterized search/limit/offset
- Joins pax8_companies to companies for matched name + active subscription count
2026-07-11 14:28:11 -04:00
a08664baae feat(14-02): add GET /api/pax8/company-matches review queue
- requireAuth-gated (D-07) list of unresolved pax8_company_match_review rows
- Bulk-fetches candidate Autotask company names in one ANY($1::bigint[]) query
- Returns items with pax8 company + zipped candidates (id/name/confidence)
2026-07-11 14:27:30 -04:00
d2dfc341da docs(14): record planning completion and pattern map
STATE.md now reflects Phase 14 as ready to execute (6 plans). Adds
14-PATTERNS.md (analog files + code excerpts) produced during planning,
consumed by execute-phase.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 14:00:38 -04:00
4a2230c457 fix(14): cite CONTEXT.md decision IDs in plan must_haves.truths
The decision-coverage-plan gate only scans designated sections
(frontmatter must_haves/truths/objective, or body sections under
matching headings) — decisions cited only in task prose/threat-model
tables don't count. Add explicit D-NN citations to the truths arrays
in Plans 01-04 so all 10 CONTEXT.md decisions are gate-visible.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 14:00:13 -04:00
4a7235c4ec fix(14): address plan-checker warnings before execution
Fix broken @file summary path references in Plans 04-06, mark
14-VALIDATION.md Wave 0 / sign-off as resolved (Plan 02 extracted +
unit-tested the resolver), and mark RESEARCH.md's two open questions
RESOLVED with the plan that closed each one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 13:56:42 -04:00
386528a011 docs(14): create phase plan — /pax8 UI surface (6 plans, 4 waves)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 13:51:00 -04:00
22fd417d17 docs(state): record phase 14 UI-SPEC session 2026-07-11 13:25:12 -04:00
5110c90f35 docs(14): UI design contract 2026-07-11 13:25:02 -04:00
5442aecb3f docs(14): record user-approved typography exception (D-10) 2026-07-11 13:22:20 -04:00
a71ca10f9b docs(14): UI design contract for /pax8 surface
Pre-populated entirely from existing DESIGN.md tokens plus Phase 14
CONTEXT.md/RESEARCH.md decisions — no new visual language introduced.
Flags the required additive DetailModal.tsx extension for the cost
breakdown drill-down.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 12:30:39 -04:00
cd33955417 docs(phase-14): add validation strategy 2026-07-11 12:19:26 -04:00
64b30a623b docs(14): research phase domain 2026-07-11 12:18:27 -04:00
ccc34110c8 docs(state): record phase 14 context session 2026-07-11 11:55:34 -04:00
4378fa5ebc docs(14): capture phase context 2026-07-11 11:55:17 -04:00
80771a4d2c docs(phase-13): evolve PROJECT.md after phase completion 2026-07-11 11:45:02 -04:00
08ab0f425c docs(phase-13): complete phase execution 2026-07-11 11:44:06 -04:00
c1ed0f9519 test(13): add phase goal verification report — human_needed
4/6 must-haves independently verified against live code and DB state
(scheduled sync fires, full pax8 sequence runs, disable/re-enable
toggle correctly gates the scheduler with DB audit columns populated).
3 items remain pending a human with an authenticated browser session
(admin UI row rendering, manual-route 403/200) — already tracked in
13-HUMAN-UAT.md. No blocking gaps found.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 11:42:44 -04:00
2798798563 docs(13): add code review report
2 critical, 3 warning, 1 info. Critical findings: unguarded POST handler
in /api/pax8/sync (no try/catch around the new integration_settings
query or PAX8 client init), and a missing admin/role permission check
on the same cost-incurring route (any authenticated session can trigger
a sync, unlike the equivalent admin toggle route).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 11:37:47 -04:00
df7322f918 test(13): persist human verification items as UAT
SC#2 (admin UI row) and the manual-route halves of SC#3/SC#4 need a
human with an authenticated browser session — tracked here so they
surface in /gsd:progress and /gsd:audit-uat rather than being silently
dropped when the phase's plan-level tracking shows complete.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 11:06:55 -04:00
50c8d5c64d docs(13-03): record partial live-verification results for Phase 13
Confirms SC#1, and the scheduler halves of SC#3/SC#4 via direct DB/log
access. Also documents the stale-Docker-image root cause found during
testing (image predated all PAX8 code; rebuilt and redeployed) and the
incidental fix needed to unblock the build. SC#2 and the manual-route
halves of SC#3/SC#4 still need a human with an authenticated browser
session — not bypassed via forged auth.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 11:06:31 -04:00