# WP1 — CapabilityDigestService (the generated program-capability digest)

## Goal
Build a NEW backend service that produces a **deterministic, bilingual "capability digest"** — a compact text block that describes every screen/feature the program has (all 13 modules) + what's new — so the AI assistant's system prompt can be built from it instead of a hand-written static string. The digest is generated from code-derived sources (never free-written), cached with a version stamp, and can be filtered to a given user's permissions. This WP delivers the service + its sources; WP2 wires it into the chat.

## Context (Moon ERP)
- Laravel modular monolith, BE at `/home/moonui/moon-erp-be`, code under `Modules/*`. Work branch `hazemdev`. Dev DB `moonui_dev_be` (⛔ never migrate:fresh/wipe; tests use sqlite via Pest). Money decimal(12,3) — N/A here. Bilingual AR/EN.
- Governing principle (from prior permissions work, Fable ruling): **"AI is the interface; the code-derived catalog is the product."** The digest MUST be assembled from real code/CHANGELOG sources, not a hand-authored prose blob. Zero PHI (features/screens only — no patient/customer data).

## Sources to assemble the digest from (verified, ranked)
1. **Screen skeleton — the shared generated capability JSON (Decision 1).** The authoritative list of every screen lives in the FRONTEND: `/home/moonui/public_html/moon-erp/src/app/core/config/nav-items.config.ts` (`NAV_MODULES`: 13 modules, ~45 groups, 121 leaf routes; each `NavItem = {label(i18n key), icon, route, permissions[], ownerOnly?}`). Labels are i18n KEYS.
   - **Approach:** add a small generator (a Node script under the FE repo, e.g. `scripts/gen-capability-map.mjs`, OR a build step) that emits a plain JSON `capability-map.json` = `[{module, group, label_en, label_ar, route, permissions[]}]` by reading `nav-items.config.ts` + resolving each `NAV.*` label from `src/assets/i18n/{en,ar}.json`. Commit the generated JSON to a location the BE can read (e.g. copy/emit into `/home/moonui/moon-erp-be/Modules/Core/resources/capability-map.json`, or read from a config path). The BE `CapabilityDigestService` reads THIS json (never parses TS). Document the regen command.
   - If wiring an FE→BE file emit is too heavy, acceptable fallback: generate the JSON once now and commit it, plus the generator script + a note that it's regenerated on demand / at deploy (Decision 6 = refresh at deploy + manual button). State clearly what you chose.
2. **Rich screen descriptions** where they exist: `Modules/Core/app/Support/PermissionCatalog.php` (RESOURCES: module→resource→{label_ar/en, screen(route), actions[]}; strong for accounting/sales/purchases/core) and `Modules/LIS/app/Support/LisScreenCatalog.php` (47 LIS screens with AR/EN descriptions). Use these to enrich the matching routes with a one-line human description. Missing description → just use the nav label.
3. **"What's new" summary (folds WP5, Decision 2):** `/home/moonui/moon-erp-be/docs/moonstack/CHANGELOG.md`. Parse the `## [Unreleased]` section + the **last 2 dated version headings** only. For each bullet, extract the bold headline + module tag; keep it SHORT (headline-level, not full paragraphs) and bilingual-aware (bullets contain `{{ar}}` splitting EN/AR — keep the side matching the requested locale, or a trimmed both). Hard token cap (see below).

## Deliverables (BE)
- **New service** `Modules/Core/app/Services/CapabilityDigestService.php` with (suggested) API:
  - `build(string $locale = 'ar', ?array $userPermissions = null): string` — returns the digest text. If `$userPermissions` given, include ONLY screens whose gating permission the user holds (Decision 4; super-admin/owner → all). Grouped by module, each line ≈ `«اسم الشاشة» (route) — وصف قصير`.
  - A `whatsNew(string $locale, int $versions = 2): string` helper (the folded WP5) — token-bounded changelog summary.
  - `version(): string` — a stable hash of the underlying sources (capability-map.json mtime/hash + CHANGELOG head hash + app version) so WP2 can version the cache and the "refresh" can bust it.
  - `cached(string $locale, ?array $userPermissions, ...): string` — wraps `build()` in Laravel cache keyed by `[locale, version(), permissions-fingerprint]`. Refreshable (a `forget()`/rebuild path for WP4's button + deploy).
- **Token budget:** the full digest (skeleton + descriptions + what's new) must stay under a safe cap (target ≤ ~6–8k tokens ≈ ~24–32k chars; the skeleton alone ~5-6k). If over, truncate the "what's new" first, then descriptions. Add a guard + a test asserting the built digest length is under the cap for the full (unfiltered) case.
- **Config:** add cap + source paths to `config/ai.php` (e.g. `ai.digest.max_chars`, `ai.digest.changelog_versions`, `ai.digest.map_path`). Do NOT remove the existing `ai.system_prompt` (WP2 reframes it as the wrapper template).

## Interfaces exposed to later WPs
- `CapabilityDigestService::build($locale, $userPermissions): string`, `::cached(...)`, `::version(): string`, and a public `refresh(): void` (clear cache) — WP2 calls `cached()`, WP4's button calls `refresh()`.
- The generated `capability-map.json` schema: `[{module, group, label_en, label_ar, route, permissions:[...]}]`.

## Acceptance criteria
- [ ] `CapabilityDigestService::build('ar')` returns a non-empty digest that mentions screens from **every** module including LIS, Clinic, Manufacturing, POS (the ones the old static prompt missed). A Pest test asserts presence of ≥1 screen from clinic + lis + pos.
- [ ] `build('en', $perms)` filters to permitted screens only (test: a limited permission set yields a strict subset; super-admin yields all).
- [ ] `whatsNew()` includes an [Unreleased] headline and stays within the version count; digest total under the char cap (test).
- [ ] `version()` changes when the capability-map or CHANGELOG head changes; stable otherwise.
- [ ] The generator script + regen command are documented in the service docblock / a short README note.

## Tests
- New `Modules/Core/tests/Unit/CapabilityDigestServiceTest.php` (Pest, sqlite): coverage of build (all-modules presence), permission filtering, locale, what's-new inclusion, token cap, version stability/change.

## Flags
- No [FIN]. No migration. Reads only (CHANGELOG, json, catalogs). The capability-map.json generation is additive.

## Out of scope
- Wiring into the chat/system-prompt (WP2). Page-context (WP3). Owner knowledge field (WP4). Don't touch `AiChatService` chat flow yet.
