Skip to main content

Solution Design Document vs. Delivered Code — Line-by-Line Mapping

Solution Design: CSM 1.0 Fault Detail Sync — Solution Design Document Prepared by: Sataware Technologies LLC SDD Date: December 16, 2025 Approved by: Phil McCaffrey, December 16, 2025 Source Reviewed: v1.0.0.73 (V23 archive, March 5, 2026) Mapping Date: March 24, 2026


This document takes every commitment Sataware made in the Solution Design Document and maps it directly to what exists — or does not exist — in the delivered source code. Nothing is added, interpreted, or inferred. If the SDD says it, we check the code.


SDD Section 1 — Introduction

"This Solution Design document outlines the technical approach for synchronizing fault-related issue data from the FAQ API into Microsoft Dynamics 365 Business Central (BC) for the CSM 1.0 Fault Detail Sync initiative."

"The design builds upon previously shared artifacts and discussions and is intended to clearly define the approved scope, execution behavior, and boundaries for implementation."

"The solution is designed to ensure alignment between Business Central and the FAQ system while preserving historical integrity, avoiding disruption to posted documents, and maintaining consistency with existing BC extensions."

Three commitments are embedded in this introduction:

SDD CommitmentDelivered?What the code shows
Ensure alignment between BC and the FAQ systemPartialCodeunit 65500 fetches data from the FAQ API and writes it into BC. But only 4 of 6 in-scope tables receive data, and alignment is one-directional with no mechanism to detect when BC and the FAQ system have drifted
Preserve historical integrityPartialNo code touches posted documents. However, codeunit 65500 lines 209–212 delete and re-insert Fault/Resol. Relationship records, which changes their SystemId and SystemCreatedAt — breaking any external system referencing those records by ID
Avoid disruption to posted documentsYesNo code in the extension reads, writes, or references any posted document table
Maintain consistency with existing BC extensionsYesThe extension respects the BestwayUSA dependency and does not conflict with other installed extensions

SDD Section 2 — Objectives

"Synchronize fault-related master data from the FAQ API into Business Central"

Partial. Codeunit 65500 ProcessStandardFormatResponse (lines 61–234) synchronizes four tables: Fault Area, Symptom Code, Fault Code, and Resolution Code. Two in-scope tables are not synchronized: Fault Area/Symptom Relationship (table 50113) is never referenced in any source file. Fault/Resolution Relationship (table 5920) receives data but through a different path — it is populated as a byproduct of the main sync loop, not as a standalone entity sync.

"Ensure BC uses only valid and active codes for new transactions"

Partial. Two of six tables have a Status field (Fault Area via TableExt 50076, Fault/Resol. Relationship via TableExt 65500). Page extensions filter these two tables on Status = "True" when opened. The remaining four tables — Symptom Code, Fault Code, Resolution Code, and Fault Area/Symptom Relationship — have no Status field. Every record on those tables remains selectable for new transactions regardless of whether it is current in the FAQ system.

"Preserve historical Service Orders, PSI records, and posted data"

Yes. No source file in the extension references any posted document table (Posted Service Invoice, Posted Service Shipment, Service Ledger Entry, etc.).

"Introduce inactive handling without deleting existing records"

Violated. Codeunit 65500 lines 209–212:

FaultResolutionRel.Delete(true);
NewFaultResolutionRel.Validate("Service Item Group Code", SerItemGrCodeBuff."Service Item Group ID");
NewFaultResolutionRel.Insert(true);

When a Fault/Resol. Relationship record needs its Service Item Group Code updated, the existing record is deleted and a new one is inserted. This is a deletion of an existing record — directly contrary to this objective.

"Provide controlled synchronization mechanisms as defined in this document"

Partial. The SDD defines three synchronization mechanisms in Section 7: a one-time full rebuild, an automated incremental sync, and stakeholder notifications. The full rebuild is partially implemented. The incremental sync does not exist — every execution is a full sync. Stakeholder notifications are implemented.


SDD Section 3 — Scope

"This Solution Design covers the synchronization of fault-related data entities between the FAQ API and Business Central, including fault areas, symptom codes, fault codes, resolution codes, and their defined relationships."

The SDD explicitly names five categories of data. Here is what the code does with each:

Data EntitySynced from FAQ API?Receives Status field?Can be marked Inactive?Filtered in UI?
Fault AreasYes — codeunit 65500 line 108Yes — TableExt 50076, field 50000YesYes — PageExt 50001 OnOpenPage filter
Symptom CodesYes — codeunit 65500 line 141NoNoNo
Fault CodesYes — codeunit 65500 line 153NoNoNo
Resolution CodesYes — codeunit 65500 line 172NoNoNo
Fault/Resolution RelationshipYes — codeunit 65500 line 185Yes — TableExt 65500, field 65500YesYes — PageExt 65501 OnOpenPage filter
Fault Area/Symptom RelationshipNo — not referenced in any source fileNoNoNo

One of six data entities is completely absent. Four of six have no inactive handling capability.


SDD Section 4 — Deliverables

"Updated BC extension logic to support FAQ API synchronization"

Partially delivered. Extension logic exists (codeunit 65500, page 65504, table extensions, page extensions). It synchronizes 4 of 6 data entities. It does not support incremental sync, inactive marking on 4 of 6 tables, or code generation.

"One-time full rebuild synchronization capability"

Partially delivered. The "First Time Sync" action on page 65504 (line 949) runs Report 65501, which iterates all Fault/Resol. Relationship records and sets their Status to "false" (Report/FaultResolCodRelationship.Report.al, line 16). It also sets the corresponding Fault Area Status to "false" (line 22). After the report runs, the user clicks "Sync Now" to import fresh data from the FAQ API. However, the rebuild only marks 2 of 6 tables as inactive — the other 4 tables have no Status field and cannot participate in the rebuild.

"Automated incremental synchronization capability"

Not delivered. There is no incremental sync in the extension. The Job Queue scheduling (page 65504, line 1005) exists and can schedule recurring executions — but every execution calls GetStandardFormat('en') which fetches the complete dataset from https://faq.bestwaycorp.com/ExternalAPI/api/1.0/standardFormat?lang=en. No "last modified" or "since" parameter is passed. No comparison between API data and existing BC data occurs. No records are marked Inactive when absent from the API response. Every scheduled run is a full rebuild, not an incremental sync.

"Stakeholder notification summary for detected changes"

Delivered. Two email notification procedures exist on page 65504:

  • SendReportByEmail (line 1165) — manual sync variant, lists all current active records
  • SendReportByEmailJQ (line 1302) — scheduled sync variant, lists records where Status changed from False to True since the last sync

Both generate styled HTML emails and send to recipients configured in the Email Recipient Setup table (65550) via BC's built-in Email codeunit. The implementation satisfies 3 of 4 notification requirements (see Section 7.3 mapping below).

"Final source code delivery"

Delivered. The V23 archive contains v1.0.0.73 source that compiles successfully and matches the version of the compiled .app binary in the sandbox.

"Supporting technical documentation"

Not delivered. No documentation exists in the delivered archive — no README, no setup guide, no API reference, no changelog, no deployment instructions, no architecture description.


SDD Section 5 — Data Entities & Tables

"The following BC tables are involved in storing and relating fault-related data, as provided in the configuration artifacts supplied by Bestway:"

  • Fault Area
  • Symptom Code
  • Fault Code
  • Resolution Code
  • Fault/Resolution Relationship
  • Fault Area/Symptom Relationship

This section lists 6 tables as in-scope. The delivered code extends 2 of them.

SDD TableBC Table IDTable Extension Delivered?Extension IDFields Added
Fault Area5915YesTableExt 50076Status (Option: "true","false")
Symptom Code5916No
Fault Code5918No
Resolution Code5919No
Fault/Resolution Relationship5920YesTableExt 65500Status (Option: "True","False"), Source (Text[10])
Fault Area/Symptom Relationship50113No

4 of 6 tables listed in the SDD have no extension at all.


SDD Section 6 — Core Design Principles

"No deletion of records once used in posted transactions"

Violated. Codeunit 65500 lines 209–212 delete Fault/Resol. Relationship records and re-insert them when the Service Item Group Code mapping changes. The code does not check whether the record being deleted is referenced by any posted transaction before deleting it.

"Inactive records retained for historical reference"

Partially met. Records on Fault Area and Fault/Resol. Relationship can be set to Status "false" and will remain in the database. Records on Symptom Code, Fault Code, Resolution Code, and Fault Area/Symptom Relationship have no Status field — there is no concept of "inactive" on those tables, so all records are treated as active regardless of their standing in the FAQ system.

"Only active values available for new transactions"

Partially met. Three page extensions add filtering:

  • PageExt 50001 (Fault Areas page): OnOpenPage sets filter Status = "true" — line 16
  • PageExt 65501 (Fault/Resol. Relationship page): OnOpenPage sets filter Status = "True" — line 42
  • PageExt 50000 (Service Order Subform): OnLookup for Fault Area Code filters Fault/Resol. Relationships by Status = "True" and Service Item Group Code — line 15

PageExt 50005 (Service Item Worksheet Subform) has the Service Item Group Code filter commented out on line 44:

// FaultAreaRel.SetRange("Service Item Group Code", Rec.ser);

This means the lookup shows all active fault areas across all product categories, ignoring the service item context.

There are no page extensions for Symptom Code, Fault Code, or Resolution Code pages. Users can select any record from those tables — active or not — on new transactions.

"Synchronization logic must be safe to re-run"

Violated. Two issues:

  1. The delete-and-reinsert pattern (codeunit 65500, lines 209–212) means re-running the sync can delete a record and recreate it with a new SystemId, SystemCreatedAt, and SystemModifiedAt. Any system that referenced the old SystemId will have an orphaned reference.

  2. The OnAfterInsert trigger on Job Queue Log Entry (TableExt 50001, line 14) calls FAQIntegration.GetStandardFormat('en') after the Job Queue has already executed codeunit 65500 via OnRun. Every scheduled execution runs the sync twice. The second run sees the first run's inserts as "already exists" and skips them — but it re-evaluates every existing record for modification, doubling the write load and producing different insert/modify counts than the first run.

"Existing extension boundaries must be respected"

Met. The extension declares its dependency on BestwayUSA (Innovia Consulting) v27.0.4.2 in app.json. No object ID conflicts with other extensions in the repository. The ID range (50000–999999) is broad but does not overlap with other extensions' reserved ranges.


SDD Section 7.1 — One-Time Full Rebuild Sync

"The one-time full rebuild sync establishes a clean baseline within Business Central by aligning all fault-related data with the FAQ API."

The "First Time Sync" action exists on page 65504 (line 949). It prompts for admin credentials via page 50001, then runs Report 65501.

"All existing fault-related records will be marked Inactive"

Partially met. Report 65501 (Report/FaultResolCodRelationship.Report.al) iterates all Fault/Resol. Relationship records and sets Status = "false" (line 16). For each record, it also looks up the corresponding Fault Area and sets its Status to match (lines 18–27).

Records on Symptom Code (5916), Fault Code (5918), Resolution Code (5919), and Fault Area/Symptom Relationship (50113) are not marked inactive because those tables have no Status field. The word "all" in the SDD means all six tables. The code marks two.

"A complete import will be performed from the FAQ API"

Met. Codeunit 65500 GetStandardFormat (line 38) calls https://faq.bestwaycorp.com/ExternalAPI/api/1.0/standardFormat?lang=en and processes the full response array. Every record in the API response is upserted into BC.

"FAQ API identifiers will be persisted as the primary reference"

Not met. The FAQ API integer IDs (e.g., csMainCategoryId = "7", issueTypeId = "184") are written directly into the BC Code field as the record's primary key. There is no separate "FAQ ID" column on Fault Area, Symptom Code, Fault Code, or Resolution Code. The BC Code field and the FAQ API identifier are the same value.

A ServiceItemGroupCodeBuffer table (50001) does store a "FAQ ID" field — but this is a manual mapping table for associating Fault Area codes with Service Item Groups. It is not a comprehensive FAQ identifier store for all six tables.

The SDD says identifiers "will be persisted as the primary reference," implying a dedicated field to store the external ID. Instead, the external ID replaced the BC code entirely. This means:

  • BC cannot have its own meaningful code values (e.g., "MOTOR-FAIL") — the codes are API integers ("7", "44")
  • If the FAQ API changes its ID scheme, every BC record's primary key must change
  • There is no way to look up a BC record by its own code — the FAQ API's ID is the code

"No legacy-to-API mapping logic will be maintained"

Met. No mapping from old BC codes to new FAQ API codes exists. The full rebuild replaces codes directly.

"Historical and posted data will remain unchanged"

Met. No code in the extension reads or writes any posted document table.


SDD Section 7.2 — Automated Incremental Sync

"Following the initial rebuild, an automated incremental synchronization process will be used to keep BC aligned with the FAQ API over time."

Not delivered. No incremental synchronization exists. What exists is a scheduled full sync. The distinction matters: the SDD describes a process that detects and applies only changes. The delivered code fetches everything and overwrites everything, every time.

"Periodic unattended execution"

Met. The ScheduleMyCodeunit action on page 65504 (line 1005) creates a BC Job Queue Entry that runs codeunit 65500 on a configurable schedule (Daily or Weekly). The Job Queue executes unattended.

"Detection of changes between API data and BC cache"

Not delivered. There is no change detection logic anywhere in the source code. Codeunit 65500 GetStandardFormat (line 48) fetches the complete dataset from /api/1.0/standardFormat — the same endpoint used for the full rebuild. No "last modified" timestamp, no "since" parameter, no pagination token, and no hash comparison is sent to the API or computed locally. The code does check whether individual field values (e.g., Description) differ before issuing a Modify (e.g., line 116–117), but this is field-level optimization within a full dataset — not change detection between the API and BC.

"Insert new records"

Met. ProcessStandardFormatResponse (codeunit 65500) checks if not FaultArea.Get(MainCategoryId) (line 108) and inserts new records when they don't exist in BC.

"Update modified records"

Met. For records that already exist, the code compares Description and Status values and issues Modify(true) when they differ (e.g., lines 116–124 for Fault Area, lines 195–214 for Fault/Resol. Relationship).

"Mark records Inactive when removed from the API"

Not delivered. There is no logic to compare the set of records returned by the API against the set of records in BC. If a Fault Area exists in BC but is absent from the API response, nothing happens — it remains active (Status = "True") in BC forever. The SDD commits to marking such records Inactive. The code does not do this.

"Maintain sync state across executions"

Partially met. A FAQ Sync Log table (50012) records each sync execution with a timestamp, sync type (Manual/Scheduled), records activated count, and user ID. The UpdateSyncLogJQ procedure (page 65504, line 1495) writes a log entry after each sync.

However, there is no per-record sync state. The log records "a sync happened at this time" — it does not record which specific records were added, modified, or should have been deactivated. There is no "last synced" timestamp on individual records. This makes it impossible to answer "when was this specific record last verified against the FAQ API?"


SDD Section 7.3 — Stakeholder Notification

"After each automated incremental sync, a notification summary will be generated to inform stakeholders of detected changes."

Notification emails are generated after both manual and scheduled syncs. Since no incremental sync exists (see Section 7.2), the notification reports are based on full sync results.

"Configurable recipient list"

Met. Table 65550 (Email Recipient Setup) stores recipient entries with User ID, User Name, and Email. Page 65551 (Email Recipient Lines) provides a lookup against BC's Users table. Recipients are loaded in both SendReportByEmail (line 1190) and SendReportByEmailJQ (line 1341).

"Summary of newly added records"

Met. Codeunit 65500 tracks FaultResolutionRelInsertCount (line 295). This count is passed to the email body via FAQ Sync Counter Manager (codeunit 65501) and displayed in the notification email's summary cards as "New (This Sync)."

"Summary of updated records"

Met. Codeunit 65500 tracks FaultResolutionRelModifyCount (line 296). This count is displayed in the notification email as "Modified (This Sync)."

"Summary of records marked Inactive"

Not delivered. No logic exists to mark records Inactive (see Section 7.2 — "Mark records Inactive when removed from the API" is not delivered). Because no records are ever deactivated by the sync, there is nothing to summarize. The JQ email reports records where Status changed from False to True (newly activated), but never the reverse (deactivated). The SDD specifically requires a summary of records marked Inactive — this cannot exist without the underlying deactivation logic.


SDD Section 8 — UI & Validation Behavior

"User-facing pages and validation logic will be updated so that only Active fault-related values are available for selection in new Service Orders, PSIs, and related transactions."

Partially met. Three page extensions add filtering for Fault Area and Fault/Resol. Relationship:

Page ExtensionExtendsFilter AppliedScope
PageExt 50001Fault AreasOnOpenPage: Status = "true"Hides inactive fault areas when the list page is opened
PageExt 65501Fault/Resol. Cod. RelationshipOnOpenPage: Status = "True"Hides inactive relationships when the list page is opened
PageExt 50000Service Order SubformOnLookup: Fault Area Code filtered by Status = "True" on related Fault/Resol. records and by Service Item Group CodeLimits fault area selection on Service Order lines to active, relevant records
PageExt 50005Service Item Worksheet SubformOnLookup: Status = "True" on Fault/Resol. records, but Service Item Group Code filter is commented out (line 44)Shows all active fault areas regardless of product — overly broad

No page extensions exist for:

  • Symptom Code selection — all records selectable
  • Fault Code selection — all records selectable
  • Resolution Code selection — all records selectable
  • Any PSI-related pages — no extensions delivered
  • Any lookup validation that prevents saving an inactive code on a new transaction

The OnOpenPage filters are soft filters — a user can clear them from the filter pane and see all records including inactive ones. There is no hard validation (e.g., an OnValidate trigger that rejects an inactive code).

"Inactive values will remain stored for historical reference but will not be selectable."

Partially met. Records with Status = "false" are retained (not deleted) on the two tables that have Status. They are hidden by the OnOpenPage filter but remain selectable if the filter is cleared. On the four tables without Status, all records are always selectable — there is no inactive state to enforce.


SDD Section 9 — Data Safety & Integrity

"No modification of posted documents"

Met. No source file references any posted document table.

"Inactive handling ensures backward compatibility"

Partially met. On Fault Area and Fault/Resol. Relationship, inactive records remain in the database and historical transactions referencing them will continue to display correctly. On the four unextended tables, there is no inactive handling — backward compatibility is maintained by default (no schema change), but there is also no ability to distinguish current codes from stale ones.

"Partial updates are avoided"

Not met. The sync loop in ProcessStandardFormatResponse (codeunit 65500, lines 96–234) processes the API response array sequentially. Each record insert or modify is committed individually — there is no wrapping transaction or rollback mechanism. If the API returns 1,000 records and an error occurs on record 500, the first 499 are committed and the remaining 501 are not. The Commit() call in UpdateSyncLogJQ (page 65504, line 1508) forces a transaction boundary that prevents rollback of the partial sync.

Additionally, the sync only operates on Fault/Resol. Relationship insert/modify counts — the insert/modify of Fault Area, Symptom Code, Fault Code, and Resolution Code records are not counted, logged, or reported. A partial failure affecting those tables would be invisible.

"Repeat executions do not create duplicate or invalid data"

Not fully met. The upsert pattern (check if exists, insert or modify) prevents simple duplicates. However:

  1. The delete-and-reinsert pattern (codeunit 65500, lines 209–212) creates a new record with a different SystemId and SystemCreatedAt each time the Service Item Group mapping changes and the sync re-runs. Any system referencing the old SystemId will hold an orphaned reference.

  2. The double execution via OnAfterInsert (TableExt 50001, line 14) means every scheduled sync runs twice. The second run's modify count includes records modified by the first run (whose SystemModifiedAt now differs from the API value check), potentially triggering unnecessary writes.


SDD Section 10 — Estimated Effort

"Total estimated effort for the scope defined in this document:"

  • ~134 hours (approximate)
  • Hourly rate: $28/hr

"This estimate reflects the combined effort for core sync functionality, one-time rebuild, automated incremental synchronization, and stakeholder notification behavior."

The estimate explicitly names four work streams:

Work StreamDelivered?
Core sync functionalityPartially — 4 of 6 tables synced, 2 of 6 tables extended, 0 of 36 specified fields
One-time rebuildPartially — marks 2 of 6 tables inactive
Automated incremental synchronizationNot delivered — every run is a full sync
Stakeholder notification behaviorDelivered — email notifications with configurable recipients

Invoice #466051 was submitted for the full estimated amount.


SDD Section 11 — Delivery Model

"The implementation will follow an outcome-based delivery model:"

"Requirements aligned via this Solution Design"

The Solution Design was approved December 16, 2025. It defines the scope, deliverables, and design principles. The delivered code does not align with this document in the areas detailed above.

"Effort estimate approval"

~134 hours at $28/hr was approved by Rob Chowdhury in December 2025.

"Final source code delivery with supporting documentation"

Source code was delivered (v1.0.0.73, March 20, 2026). Supporting documentation was not delivered — no README, no setup guide, no API documentation, no deployment instructions, no changelog, no architecture description.


Summary — Commitment Scorecard

The SDD contains 33 distinct, verifiable commitments across Sections 2–9 and 11. Each commitment is scored below.

#SDD SectionCommitmentDelivered?
12Synchronize fault-related master data from FAQ API into BCPartial
22Ensure BC uses only valid and active codes for new transactionsPartial
32Preserve historical Service Orders, PSI records, and posted dataYes
42Introduce inactive handling without deleting existing recordsNo — records are deleted (line 210)
52Provide controlled synchronization mechanisms as defined in this documentPartial
64Updated BC extension logic to support FAQ API synchronizationPartial
74One-time full rebuild synchronization capabilityPartial
84Automated incremental synchronization capabilityNo
94Stakeholder notification summary for detected changesYes
104Final source code deliveryYes
114Supporting technical documentationNo
126No deletion of records once used in posted transactionsNo — Delete(true) on line 210
136Inactive records retained for historical referencePartial — 2 of 6 tables
146Only active values available for new transactionsPartial — 2 of 6 tables
156Synchronization logic must be safe to re-runNo — delete-reinsert + double execution
166Existing extension boundaries must be respectedYes
177.1All existing fault-related records will be marked InactivePartial — 2 of 6 tables
187.1A complete import will be performed from the FAQ APIYes
197.1FAQ API identifiers will be persisted as the primary referenceNo — API IDs used as BC Code values, no separate field
207.1No legacy-to-API mapping logic will be maintainedYes
217.1Historical and posted data will remain unchangedYes
227.2Periodic unattended executionYes
237.2Detection of changes between API data and BC cacheNo
247.2Insert new recordsYes
257.2Update modified recordsYes
267.2Mark records Inactive when removed from the APINo
277.2Maintain sync state across executionsPartial — log exists but no per-record state
287.3Configurable recipient listYes
297.3Summary of newly added recordsYes
307.3Summary of updated recordsYes
317.3Summary of records marked InactiveNo — deactivation logic does not exist
328Only Active values available for selection in new Service Orders, PSIs, and related transactions; inactive values not selectablePartial — 2 of 6 tables, soft filters only
339No modification of posted documentsYes
349Inactive handling ensures backward compatibilityPartial — 2 of 6 tables
359Partial updates are avoidedNo — no transaction wrapping
369Repeat executions do not create duplicate or invalid dataNo — delete-reinsert changes SystemId
3711Final source code delivery with supporting documentationPartial — source delivered, documentation not delivered

Totals

VerdictCount%
Yes — fully delivered as committed1335%
Partial — partially delivered, material gaps remain1335%
No — not delivered or directly violated1130%
Total commitments37