Overall readiness for an exit onto owned code, scored from your metadata.
Significant custom logic
Plan for guided translation — the deterministic core is smaller in this org.
This score is coverage of auto-transcription: the share of inventoried items that convert deterministically today, with no AI in the loop. Validation-rule formulas outside the deterministic subset are counted against it, so the number is honest rather than flattering.
Category-by-category, in the Readiness-Report rhythm: what is ready, what needs attention, what is blocked. Each metadata item weighs 1. Validation rules whose formulas fall outside the deterministic subset are counted against today’s coverage — they were flagged by running the actual generator on your rules.
Transcribed today — deterministic transcription, running now, no AI in the loop.
| Artifact | Count |
|---|---|
| Objects → PostgreSQL tables (Prisma models) | 14 |
| Fields → typed columns | 34 |
| Validation rules → Zod validators (formula subset) | 0 |
| Record types → per-variant schemas | 0 |
| List views → table configs + SQL filters | 1 |
| Search layouts → Postgres full-text indexes | 2 |
| Permission sets → RBAC policies + row security | 9 |
| Page layouts → React detail + edit views | 9 |
| Custom applications → app nav + switcher modules regenerated from each CustomApplication's ordered tabs by the real app parser — transcribe emits these today | 1 |
| Custom Metadata records — seeded as config data each *.md-meta.xml parsed by the real parser and proven seedable by the real seed generator against the transcribed __mdt objects — transcribe emits data/seed-custom-metadata.ts | 11 |
Translation required — Apex, Flows and out-of-subset formulas go through the LLM + verification harness.
| Artifact | Count |
|---|---|
| Validation-rule formulas outside the deterministic subset flagged by the real generator, not estimated | 0 |
| Apex classes 17,650 lines, 180 SOQL statements — 158 (87.8%) already translate to SQL deterministically | 139 |
| Apex triggers | 3 |
| Flows 2 elements to translate | 1 |
| Workflow rules | 0 |
| LWC components — template converted, behavior needs a person render path auto-converted to JSX; @wire / imperative behavior stubbed and marked for a human to finish (see Components section) | 1 |
Inventoried but not yet in either automated pipeline — scoped for human work (UI rewrites, endpoint design) or awaiting an engine surface; counted against readiness so the score stays honest.
| Artifact | Count |
|---|---|
| Profiles (permission sets cover the RBAC path today) | 0 |
| Email templates the classifier can't auto-render | 0 |
| Reports the SQL generator refuses | 0 |
| Dashboards not fully rendered | 0 |
| Integration points (named credentials, connected apps, remote sites) see Integrations section — endpoints need a human-designed replacement | 1 |
| Sharing metadata (roles, sharing rules files) | 0 |
| Custom UI components — manual rewrite (flagged LWC + all Aura) no deterministic path — Aura and render-path-blocked LWC need a human rewrite; see Components section | 6 |
| Unhandled metadata · .md Unrecognized metadata type — no pipeline claims it and it is not known to be inert; a person must assess it. | 74 |
| Unhandled metadata · .dwl Unrecognized metadata type — no pipeline claims it and it is not known to be inert; a person must assess it. | 14 |
| Unhandled metadata · .dwl-meta.xml Unrecognized metadata type — no pipeline claims it and it is not known to be inert; a person must assess it. | 14 |
| Unhandled metadata · .resource-meta.xml A Static Resource is a file (image/zip/JS/CSS) served as-is; copied verbatim into the owned app's assets, with no schema or logic to transpile (a bundled JS library is carried over unchanged). (Metadata API catalog classifies StaticResource as "nothing-to-migrate", but that is documented, not generator-proven here — so it is counted against readiness fail-closed until a pipeline verifies it.) | 6 |
| Unhandled metadata · .cachepartition-meta.xml Allocates Salesforce Platform Cache capacity (a runtime performance-tuning construct); the owned stack uses its own caching (Redis/etc.), so there is nothing to migrate. (Metadata API catalog classifies PlatformCachePartition as "nothing-to-migrate", but that is documented, not generator-proven here — so it is counted against readiness fail-closed until a pipeline verifies it.) | 1 |
| Unhandled metadata · .docx Unrecognized metadata type — no pipeline claims it and it is not known to be inert; a person must assess it. | 1 |
| Unhandled metadata · .flexipage-meta.xml Lightning page (flexipage) — the saved config of Salesforce's Lightning App Builder (its drag-and-drop page-layout tool). Each page is parsed and labeled per-page in the Lightning pages section, and its layout semantics (highlights / detail / related lists) are reproduced by the generated record layouts. Layout editing on the owned CRM is answered by an editable layout config: admins edit a served JSON config (field order, sections) that takes effect on refresh with no redeploy, and a drag-and-drop editor can layer on later. Translating this specific page's config into that layout config is a per-page transpile not yet proven per item, so it is counted against readiness. — Apex_Recipes | 1 |
| Unhandled metadata · .labels-meta.xml Custom labels — named display strings (i18n). transcribe already reads them (parseCustomLabels) to resolve @salesforce/label references during component emit, but it does not yet emit them as a standalone i18n message catalog the owned app ships, so they stay counted against readiness until that surface is built (copied as an i18n resource, not transpiled). | 1 |
| Unhandled metadata · .permissionsetgroup-meta.xml Composes several permission sets (with muting) into one grant; the individual permission sets are transcribed to RBAC, but group composition/muting is not yet combined in the RBAC generator — counted against readiness. (Metadata API catalog: PermissionSetGroup.) | 1 |
| Unhandled metadata · .prompt-meta.xml An In-App Guidance prompt/walkthrough (onboarding tooltip) bound to Salesforce's Lightning UI; there is no equivalent overlay surface in the generated app, so there is nothing to migrate. (Metadata API catalog classifies Prompt as "nothing-to-migrate", but that is documented, not generator-proven here — so it is counted against readiness fail-closed until a pipeline verifies it.) | 1 |
| Unhandled metadata · .resource Unrecognized metadata type — no pipeline claims it and it is not known to be inert; a person must assess it. | 1 |
Directories in the retrieve that the project’s package scope excluded — counted here for disclosure, not folded into the readiness score.
This org declares a package scope in sfdx-project.json, so the scan looked only inside its packageDirectories. The directories below exist in the retrieve but sit outside that scope — nothing in them is counted in the readiness score above, including any reports, dashboards, or objects they hold. A full migration retrieve should include them if they carry production metadata; re-run the X-Ray against a full retrieve to fold them in.
| Directory (unscanned) | Files | Recognized metadata inside (count only) |
|---|---|---|
data/ | 15 | no recognized metadata types |
.github/ | 12 | no recognized metadata types |
bin/ | 3 | no recognized metadata types |
.husky/ | 2 | no recognized metadata types |
.vscode/ | 1 | no recognized metadata types |
config/ | 1 | no recognized metadata types |
Unrecognized metadata a person would do nothing with — each stated with a defensible reason and excluded from the readiness denominator, so the “needs a person” count reflects real work, not inert files.
4 file(s) across 3 type(s) carry no data model and no logic a CRM replacement must reproduce — localized label translations, binary/static assets, display-only or theming metadata, build/test tooling. Each is excluded from the “needs a person” count and the human-work denominator, with a per-type reason stated so a skeptical reviewer can challenge any single line. Nothing is hidden.
| Type / family | Files | Why there is nothing to migrate |
|---|---|---|
.tab-meta.xml | 2 | CustomTab — a navigation container only; app navigation is regenerated from CustomApplication, and a tab carries no data or logic of its own. |
.png | 1 | PNG image — binary/static asset served as-is by any CRM; nothing to transpile or model. |
project/build config | 1 | Salesforce project/build config (SFDX / npm / ESLint / Jest / Babel tooling) — dev-time only, not part of the running org; nothing to migrate (discard). |
Surfaces the X-Ray looked for and found zero of in this org — so absence reads as “checked, none found”, not “never looked”.
Surfaces the X-Ray actively looked for in this org and found none of. Listed so a zero reads as “checked, none found” — not “never looked”. Each maps to a real recognizer (an inventory counter or a documented Metadata API type).
Reports · Dashboards · Workflow rules · Approval processes · Email templates · Record types · Connected apps · Remote site settings · Roles · Sharing rules · Queues · Assignment rules · Escalation rules · Auto-response rules · Duplicate rules · Matching rules · Territory management · Forecasting types · Global value sets · Public groups · Quick actions
An ordered plan built from what this org actually contains — steps for artifact types you don’t have are omitted.
What a migration of this org produces and what remains as translation work.
| Deliverable | Quantity |
|---|---|
| PostgreSQL tables (Prisma models) | 14 |
| Typed columns | 34 |
| Validators (Zod) 0 of 0 formulas need manual/LLM translation | 0 |
| Access policies (RBAC + row security) | 9 |
| Generated views (React detail/edit + list views) | 19 |
| Full-text search indexes | 2 |
| Flows to translate 2 elements total | 1 |
| Apex classes to translate 17,650 source lines, 180 SOQL statements — 158 → SQL deterministically today | 139 |
| Apex triggers to translate | 3 |
Seat count / per-seat cost not provided — the license-exposure comparison is omitted rather than estimated. Re-run the X-Ray with those two numbers to see annual spend vs one-time conversion.
Provide --seats N --cost PERSEAT_MONTHLY to the X-Ray to
model the savings of replacing Salesforce with a stack you own.
| Workstream | Man-hours | Basis (quantity × rate) |
|---|---|---|
| Apex translation | 787.1 h | COMPLEX 1,282 code lines × 0.3; STANDARD 1,809 code lines × 0.12; MECHANICAL 989 code lines × 0.05; TRIVIAL 11 code lines × 0 (automated); TEST 68 class(es) × 2 h/class (parity capture + golden fill; UNCALIBRATED) |
| Component rewrite (LWC/Aura) | 102 h | 1 partial × 6 h + 6 flagged × 16 h (0 auto-converted × 0) |
| Integration re-implementation | 156 h | 13 endpoint(s) × 12 h |
| Unhandled metadata (needs a person) | 345 h | 115 item(s) × 3 h |
| Data-migration dry-runs | 56 h | 14 object(s) × 4 h |
| Build subtotal | 1,446.1 h | sum of workstreams |
| Code review (15% of build) | 216.9 h | on the build critical path |
| QA (40% of build) | 578.5 h | parallel stream, 30% lag |
| Total man-hours (pre-buffer) | 2,241.5 h | build + review + QA |
| Schedule (parallel QA, critical path over 3) | Value |
|---|---|
| Build calendar (build ÷ team) | 554.3 h |
| QA calendar (QA ÷ team) | 192.8 h |
| QA start lag | 166.3 h |
| Critical path = max(build, lag + QA) | 554.3 h |
| Calendar (+20% buffer) | 22.2 weeks ≈ 5.1 months |
Budget: $403,470 = 2,689.8 h (incl. 20% buffer) × $150/h.
Outbound/inbound integration points this org depends on — counted and mapped where an owned-stack equivalent exists, flagged honestly where it doesn't.
Named credentials, connected apps, remote-site entries, and outbound Apex callouts this org depends on. Endpoint business logic and live credentials are never inspected or fabricated — only counted and mapped where an owned-stack equivalent exists.
| Kind | Count |
|---|---|
namedCredential | 1 |
apexCallout | 13 |
14 integration point(s) total — 1 mapped to an owned-stack equivalent, 13 flagged for human design work.
LWC/Aura bundles found on disk — LWC run through the real deterministic converter, Aura scoped for manual rewrite.
Custom UI (Lightning Web Components / Aura). LWC templates and the mechanical slice of their JavaScript are converted to a compiling React .tsx by the real deterministic converter (src/translate/lwc-convert.ts) — the same fail-closed posture as the SOQL translator: any construct outside the directive table becomes a NAMED blocker, never a faked translation. Aura is a different framework with no converter and stays 100% manual.
| Components found | 7 |
| LWC / Aura | 7 / 0 |
| LWC converted (deterministic .tsx, zero blockers) | 0 |
| LWC partial (template converted, behavior needs a person) | 1 |
| LWC flagged (render-path blocker — manual rewrite) | 6 |
| Aura (manual rewrite — no converter) | 0 |
| Component | Verdict | Blockers (construct + phase) |
|---|---|---|
apexRecipesContainer | partial | depends on unconverted child <RecipeTreeView> (js); depends on unconverted child <RelatedCodeTabs> (js) |
errorPanel | flagged | import from c/ldsUtils (js); getter errorMessages not mechanically convertible (js); lifecycle render() (js); JS service module (no template — not a rendered component) (template) |
formattedDocsViewer | flagged | lightning module import (lightning/platformResourceLoader) (js); @salesforce platform import (@salesforce/resourceUrl/markdownIt) (js); @salesforce platform import (@salesforce/resourceUrl/highlight) (js); @salesforce platform import (@salesforce/resourceUrl/documentation) (js) — +8 more |
formattedRecipeDisplay | flagged | lightning module import (lightning/platformResourceLoader) (js); @salesforce platform import (@salesforce/resourceUrl/highlight) (js); @salesforce/apex import (FormattedRecipeDisplayController.getRecipeCode) (js); @wire getRecipeCode (js) — +5 more |
ldsUtils | flagged | JS service module (no template — not a rendered component) (template) |
recipeTreeView | flagged | @salesforce/apex import (RecipeTreeViewController.generateTreeData) (js); lifecycle connectedCallback() (js); handler handleTreeItemSelect not mechanically convertible (js); base component <lightning-tree> (template) |
relatedCodeTabs | flagged | @salesforce/apex import (RelatedCodeTabsController.getRelatedClasses) (js); base component <lightning-tabset> (template) |
0 of 7 LWC (0.0%) convert to a compiling React .tsx deterministically; 1 convert their template only (behavior stubbed for a person); 6 need a full manual rewrite. All 0 Aura component(s) are 100% manual — a different framework with no converter.
Record / app / home page composition — a per-page readiness label. Transparency, not coverage: these are already counted in “Needs a person” above.
Lightning pages (flexipages) are a needs-a-person surface — this labeler names, per page, WHY; it does not claim to build them. None of the 1 page(s) are standard-only record pages a generated layout reproduces. Every page here is already counted once against readiness via the .flexipage-meta.xml line in “Needs a person” above — this subsection is transparency only and changes no count.
| Page | Type | Object | Verdict | Why it needs a person |
|---|---|---|---|---|
Apex_Recipes | AppPage | — | needs a person | custom LWC/Aura c:apexRecipesContainer needs rewrite as an owned React component (see Components section). |
0 covered (layout semantics) · 1 needs a person · 1 page(s) total.
Per-class conversion inventory of every Apex file — classified by measured properties, never by a time estimate.
Every *.cls / *.trigger classified by measured properties only — code lines, method count, embedded SOQL, and risk markers (callouts, async, dynamic SOQL) — never by a time estimate. The deterministic verdict is the real pre-pass: TRIVIAL files translate today with no AI in the loop; TEST classes are regenerated as a parity harness, not translated line-for-line.
| Apex files | 142 |
| classes / triggers / interfaces / enums | 138 / 3 / 0 / 1 |
| Code lines (of 17,650 total) | 11,890 |
| Methods (parsed) | 679 |
| Deterministically translatable files (no LLM) | 2 |
| Callout / async / @AuraEnabled / test classes | 13 / 12 / 5 / 68 |
| SOQL — total / deterministic / flagged | 180 / 158 / 22 |
| DML statements | 127 |
| Parse failures (method count unknown, flagged) | 0 |
| Bucket | Files | Code lines |
|---|---|---|
| COMPLEX carries real risk — callouts, async (@future / Queueable / Batchable / Schedulable), dynamic SOQL, or large / high-method. | 18 | 1,282 |
| STANDARD ordinary business logic between the mechanical and complex boundaries. | 14 | 1,809 |
| MECHANICAL small and bounded — few methods and SOQL, no callouts, async, or dynamic SOQL; a low-branching translation. | 40 | 989 |
| TRIVIAL the deterministic pre-pass translates these today — no LLM, no cost (enums, interfaces, DTOs, constants, empty exceptions). | 2 | 11 |
| TEST regenerated as a parity harness, not translated line-for-line. | 68 | 7,799 |
| Class | Kind | Bucket | Code lines |
|---|---|---|---|
DMLRecipes_Tests | class | TEST | 752 |
CustomRestEndpointRecipes_Tests | class | TEST | 610 |
SOQLRecipes_Tests | class | TEST | 436 |
Safely_Tests | class | TEST | 387 |
CalloutRecipes_Tests | class | TEST | 370 |
StripInaccessibleRecipes_Tests | class | TEST | 342 |
TriggerHandler_Test | class | TEST | 300 |
EncryptionRecipes | class | STANDARD | 243 |
TriggerHandler | class | STANDARD | 243 |
AccountTriggerHandler_Tests | class | TEST | 229 |
LLM assessment: not run (key-gated per engagement).
What the real report/dashboard generator can translate to SQL/config today vs what it honestly refuses.
Reports translate to a single deterministic SQL SELECT when their shape allows it (Tabular/Summary, implicit-AND filters, no custom summary formulas); Matrix/joined reports and other unsupported shapes are honestly refused, never approximated. Dashboard panels are resolved through the SAME translate/refuse machinery: a panel renders only when it binds exactly to what its backing report produces, and is refused — by construct — whenever the value would have to be fabricated (a renderable chart kind alone is not enough).
| Reports | 0 |
| auto-translatable to SQL | 0 |
| refused (see reasons below) | 0 |
| Dashboards | 0 |
| fully rendered (every panel) | 0 |
| panels rendered | 0 |
| panels refused (see reasons below) | 0 |
Computed fields, classified by the owned-stack construct each becomes.
Computed fields, split by the owned-stack construct they become: a same-object formula becomes a Postgres GENERATED ALWAYS AS column; a cross-object formula becomes a query-time resolver (generated columns can't reference another table's row); a roll-up summary becomes a trigger-maintained aggregate. Anything outside that subset is flagged, never guessed.
| Generated columns (same-object formulas) | 0 |
| Rollup triggers (roll-up summaries) | 0 |
| Query-time resolvers (cross-object formulas) | 0 |
| Flagged (outside the supported subset) | 0 |
0 computed field(s) classified total.
Everything found in the metadata snapshot, by type — the raw counts behind the readiness score above.
| Metadata | Count |
|---|---|
| Objects | 14 |
| Fields | 34 |
| Validation rules | 0 |
| Record types | 0 |
| List views | 1 |
| Search layouts | 2 |
| Permission sets | 9 |
| Page layouts | 9 |
| Profiles | 0 |
| Flows | 1 (2 elements) |
| Apex classes | 139 |
| Apex triggers | 3 |
| Apex source lines | 17,650 |
| SOQL statements (measured) | 180 |
| SOQL translating deterministically today | 158 (87.8%) |
| Workflow rules | 0 |
| Email templates | 0 |
| Reports | 0 |
| Other: .cachepartition-meta.xml | 1 |
| Other: .csptrustedsite-meta.xml | 1 |
| Other: .css | 1 |
| Other: .docx | 1 |
| Other: .dwl | 14 |
| Other: .dwl-meta.xml | 14 |
| Other: .flexipage-meta.xml | 1 |
| Other: .js | 2 |
| Other: .json | 1 |
| Other: .labels-meta.xml | 1 |
| Other: .md | 74 |
| Other: .permissionsetgroup-meta.xml | 1 |
| Other: .png | 1 |
| Other: .prompt-meta.xml | 1 |
| Other: .resource | 1 |
| Other: .resource-meta.xml | 6 |
| Other: .tab-meta.xml | 2 |
| Total files scanned | 518 |
| Element | Count |
|---|---|
recordLookups | 1 |
start | 1 |