@netoalmanca/advpl-sensei 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/agents/changelog-generator.md +63 -0
  2. package/agents/code-generator.md +215 -0
  3. package/agents/code-reviewer.md +145 -0
  4. package/agents/debugger.md +83 -0
  5. package/agents/doc-generator.md +67 -0
  6. package/agents/docs-reference.md +86 -0
  7. package/agents/migrator.md +84 -0
  8. package/agents/process-consultant.md +97 -0
  9. package/agents/refactorer.md +75 -0
  10. package/agents/sx-configurator.md +67 -0
  11. package/commands/changelog.md +66 -0
  12. package/commands/diagnose.md +67 -0
  13. package/commands/docs.md +81 -0
  14. package/commands/document.md +67 -0
  15. package/commands/explain.md +60 -0
  16. package/commands/generate.md +111 -0
  17. package/commands/migrate.md +81 -0
  18. package/commands/process.md +111 -0
  19. package/commands/refactor.md +65 -0
  20. package/commands/review.md +60 -0
  21. package/commands/sxgen.md +98 -0
  22. package/commands/test.md +103 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +143 -0
  26. package/dist/index.js.map +1 -0
  27. package/package.json +30 -0
  28. package/skills/advpl-code-generation/SKILL.md +163 -0
  29. package/skills/advpl-code-generation/patterns-fwformbrowse.md +485 -0
  30. package/skills/advpl-code-generation/patterns-jobs.md +519 -0
  31. package/skills/advpl-code-generation/patterns-mvc.md +765 -0
  32. package/skills/advpl-code-generation/patterns-pontos-entrada.md +708 -0
  33. package/skills/advpl-code-generation/patterns-rest.md +974 -0
  34. package/skills/advpl-code-generation/patterns-soap.md +639 -0
  35. package/skills/advpl-code-generation/patterns-treport.md +481 -0
  36. package/skills/advpl-code-generation/patterns-workflow.md +779 -0
  37. package/skills/advpl-code-generation/templates-classes.md +1096 -0
  38. package/skills/advpl-code-review/SKILL.md +72 -0
  39. package/skills/advpl-code-review/rules-best-practices.md +444 -0
  40. package/skills/advpl-code-review/rules-modernization.md +290 -0
  41. package/skills/advpl-code-review/rules-performance.md +333 -0
  42. package/skills/advpl-code-review/rules-security.md +302 -0
  43. package/skills/advpl-debugging/SKILL.md +265 -0
  44. package/skills/advpl-debugging/common-errors.md +1124 -0
  45. package/skills/advpl-debugging/performance-tips.md +768 -0
  46. package/skills/advpl-refactoring/SKILL.md +139 -0
  47. package/skills/advpl-to-tlpp-migration/SKILL.md +293 -0
  48. package/skills/advpl-to-tlpp-migration/migration-checklist.md +122 -0
  49. package/skills/advpl-to-tlpp-migration/migration-rules.md +265 -0
  50. package/skills/changelog-patterns/SKILL.md +99 -0
  51. package/skills/code-explanation/SKILL.md +66 -0
  52. package/skills/documentation-patterns/SKILL.md +172 -0
  53. package/skills/embedded-sql/SKILL.md +379 -0
  54. package/skills/probat-testing/SKILL.md +226 -0
  55. package/skills/probat-testing/patterns-unit-tests.md +614 -0
  56. package/skills/protheus-business/SKILL.md +92 -0
  57. package/skills/protheus-business/modulo-compras.md +780 -0
  58. package/skills/protheus-business/modulo-contabilidade.md +874 -0
  59. package/skills/protheus-business/modulo-estoque.md +876 -0
  60. package/skills/protheus-business/modulo-faturamento.md +800 -0
  61. package/skills/protheus-business/modulo-financeiro.md +1015 -0
  62. package/skills/protheus-business/modulo-fiscal.md +749 -0
  63. package/skills/protheus-business/modulo-manutencao.md +848 -0
  64. package/skills/protheus-business/modulo-pcp.md +743 -0
  65. package/skills/protheus-reference/SKILL.md +119 -0
  66. package/skills/protheus-reference/native-functions.md +7029 -0
  67. package/skills/protheus-reference/rest-api-reference.md +1758 -0
  68. package/skills/protheus-reference/restricted-functions.md +265 -0
  69. package/skills/protheus-reference/sx-dictionary.md +854 -0
  70. package/skills/sx-configuration/SKILL.md +184 -0
@@ -0,0 +1,302 @@
1
+ # Security Rules
2
+
3
+ Rules for detecting security vulnerabilities in ADVPL/TLPP code. Each rule includes a detection pattern, violation example, correct example, and explanation.
4
+
5
+ ---
6
+
7
+ ## [SEC-001] SQL built by string concatenation without %exp: macro (SQL injection risk)
8
+
9
+ **Severity:** CRITICAL
10
+
11
+ **Description:** Building SQL queries by concatenating user-supplied or external variables directly into the query string allows SQL injection attacks. Attackers can manipulate input to execute arbitrary SQL commands, potentially reading, modifying, or deleting data.
12
+
13
+ **What to look for:** `TCQuery` or string-based SQL construction where variables are concatenated with `+` instead of using BeginSQL with `%exp:variable%` macro substitution.
14
+
15
+ **Violation:**
16
+
17
+ ```advpl
18
+ User Function SearchClient(cSearch)
19
+ Local cQuery := ""
20
+
21
+ // DANGEROUS: cSearch is concatenated directly into SQL
22
+ cQuery := "SELECT A1_COD, A1_NOME FROM " + RetSqlName("SA1")
23
+ cQuery += " WHERE A1_NOME LIKE '%" + cSearch + "%'"
24
+ cQuery += " AND D_E_L_E_T_ = ' '"
25
+
26
+ TCQuery cQuery New Alias "QRY_CLI"
27
+
28
+ // If cSearch = "'; DROP TABLE SA1; --"
29
+ // the query becomes destructive!
30
+
31
+ Return
32
+ ```
33
+
34
+ **Correct:**
35
+
36
+ ```advpl
37
+ User Function SearchClient(cSearch)
38
+ Local cAlias := GetNextAlias()
39
+ Local cFilter := "%" + cSearch + "%"
40
+
41
+ BeginSQL Alias cAlias
42
+ SELECT SA1.A1_COD, SA1.A1_NOME
43
+ FROM %table:SA1% SA1
44
+ WHERE SA1.%notDel%
45
+ AND SA1.A1_FILIAL = %xfilial:SA1%
46
+ AND SA1.A1_NOME LIKE %exp:cFilter%
47
+ EndSQL
48
+
49
+ Return
50
+ ```
51
+
52
+ **Why it matters:** SQL injection is one of the most exploited vulnerabilities in web applications and internal systems alike. In Protheus, an injected query could bypass access controls, extract sensitive financial data, or corrupt critical business tables. The `%exp:` macro safely parameterizes values, preventing injection.
53
+
54
+ ---
55
+
56
+ ## [SEC-002] REST endpoint using SELF:GetContent() without input validation
57
+
58
+ **Severity:** CRITICAL
59
+
60
+ **Description:** REST API endpoints that read request body content via `SELF:GetContent()` (or `oRest:GetBody()`) and use the data directly without validation expose the system to injection attacks, type errors, and business logic bypass.
61
+
62
+ **What to look for:** `SELF:GetContent()`, `oRest:GetBody()`, or similar request body reading methods where the returned content is used directly in SQL queries, database operations, or business logic without validation or sanitization.
63
+
64
+ **Violation:**
65
+
66
+ ```tlpp
67
+ @Get("/api/v1/clients")
68
+ Method GetClient() Class ClientService
69
+ Local cBody := SELF:GetContent()
70
+ Local jBody := JsonObject():New()
71
+ Local cCodCli := ""
72
+
73
+ jBody:FromJson(cBody)
74
+ cCodCli := jBody["code"] // No validation!
75
+
76
+ // Used directly in database lookup
77
+ DbSelectArea("SA1")
78
+ DbSetOrder(1)
79
+ DbSeek(xFilial("SA1") + cCodCli)
80
+
81
+ // cCodCli could be NIL, empty, oversized, or contain
82
+ // malicious data - no checks performed
83
+
84
+ Return
85
+ ```
86
+
87
+ **Correct:**
88
+
89
+ ```tlpp
90
+ @Get("/api/v1/clients")
91
+ Method GetClient() Class ClientService
92
+ Local cBody := SELF:GetContent()
93
+ Local jBody := JsonObject():New()
94
+ Local cCodCli := ""
95
+ Local nRet := jBody:FromJson(cBody)
96
+
97
+ // Validate JSON parsing
98
+ If nRet <> 0
99
+ SELF:SetResponse('{"error": "Invalid JSON body"}')
100
+ SELF:SetStatus(400)
101
+ Return
102
+ EndIf
103
+
104
+ // Validate required field existence and type
105
+ If ValType(jBody["code"]) <> "C" .Or. Empty(jBody["code"])
106
+ SELF:SetResponse('{"error": "Field code is required and must be a string"}')
107
+ SELF:SetStatus(400)
108
+ Return
109
+ EndIf
110
+
111
+ // Validate field length and content
112
+ cCodCli := PadR(AllTrim(jBody["code"]), TamSX3("A1_COD")[1])
113
+
114
+ DbSelectArea("SA1")
115
+ DbSetOrder(1)
116
+ If DbSeek(xFilial("SA1") + cCodCli)
117
+ // Process valid client
118
+ Else
119
+ SELF:SetResponse('{"error": "Client not found"}')
120
+ SELF:SetStatus(404)
121
+ EndIf
122
+
123
+ Return
124
+ ```
125
+
126
+ **Why it matters:** REST endpoints are exposed to external consumers and potentially the public internet. Without input validation, attackers can send malformed payloads that cause runtime errors (crashing the thread), bypass business rules, or exploit downstream operations. Every input must be validated for type, length, format, and business constraints.
127
+
128
+ ---
129
+
130
+ ## [SEC-003] Sensitive data in ConOut/FWLogMsg output
131
+
132
+ **Severity:** WARNING
133
+
134
+ **Description:** Logging sensitive information such as passwords, API tokens, CPF/CNPJ numbers, credit card numbers, or personal data in `ConOut` or `FWLogMsg` exposes it to anyone with access to the AppServer console or log files.
135
+
136
+ **What to look for:** `ConOut` or `FWLogMsg` calls that output variables containing passwords, tokens, credentials, CPF, CNPJ, or any personally identifiable information (PII).
137
+
138
+ **Violation:**
139
+
140
+ ```advpl
141
+ User Function AuthenticateUser(cUser, cPassword)
142
+ Local lOk := .F.
143
+
144
+ // DANGER: password logged in plain text!
145
+ ConOut("[Auth] Attempting login - User: " + cUser + " Password: " + cPassword)
146
+
147
+ lOk := ValidateCredentials(cUser, cPassword)
148
+
149
+ If !lOk
150
+ FWLogMsg("WARNING", , "AUTH", "Security", "", 01, ;
151
+ "Failed login for user: " + cUser + " with password: " + cPassword)
152
+ EndIf
153
+
154
+ Return lOk
155
+ ```
156
+
157
+ **Correct:**
158
+
159
+ ```advpl
160
+ User Function AuthenticateUser(cUser, cPassword)
161
+ Local lOk := .F.
162
+
163
+ ConOut("[Auth] Attempting login - User: " + cUser)
164
+
165
+ lOk := ValidateCredentials(cUser, cPassword)
166
+
167
+ If !lOk
168
+ FWLogMsg("WARNING", , "AUTH", "Security", "", 01, ;
169
+ "Failed login attempt for user: " + cUser)
170
+ EndIf
171
+
172
+ Return lOk
173
+ ```
174
+
175
+ **Why it matters:** Log files are often stored unencrypted, shared across teams, and retained for long periods. Sensitive data in logs can be accessed by unauthorized personnel, leaked through log aggregation tools, or exposed in security breaches. Regulations like LGPD (Brazil) and GDPR explicitly require that personal data not be logged unnecessarily.
176
+
177
+ ---
178
+
179
+ ## [SEC-004] Hardcoded credentials in source code
180
+
181
+ **Severity:** WARNING
182
+
183
+ **Description:** Passwords, API keys, database connection strings, and other credentials must never be hardcoded in source code. Source code is stored in version control, compiled into RPO, and accessible to all developers, making hardcoded secrets a significant security risk.
184
+
185
+ **What to look for:** String literals that appear to be passwords, API keys, bearer tokens, connection strings, or authentication secrets assigned to variables or used directly in function calls.
186
+
187
+ **Violation:**
188
+
189
+ ```advpl
190
+ User Function ConnectAPI()
191
+ Local cUrl := "https://api.example.com/v1"
192
+ Local cApiKey := "sk-abc123def456ghi789jkl012mno345"
193
+ Local cPass := "P@ssw0rd!2025"
194
+ Local aHeaders := {}
195
+
196
+ aAdd(aHeaders, "Authorization: Bearer " + cApiKey)
197
+ aAdd(aHeaders, "Content-Type: application/json")
198
+
199
+ cResponse := HttpGet(cUrl + "/data", "", aHeaders)
200
+
201
+ Return cResponse
202
+ ```
203
+
204
+ **Correct:**
205
+
206
+ ```advpl
207
+ User Function ConnectAPI()
208
+ Local cUrl := "https://api.example.com/v1"
209
+ Local cApiKey := GetAPICredential("EXAMPLE_API_KEY")
210
+ Local aHeaders := {}
211
+
212
+ If Empty(cApiKey)
213
+ ConOut("[ConnectAPI] API key not configured. Check SX6 parameter EXAMPLE_API_KEY.")
214
+ Return ""
215
+ EndIf
216
+
217
+ aAdd(aHeaders, "Authorization: Bearer " + cApiKey)
218
+ aAdd(aHeaders, "Content-Type: application/json")
219
+
220
+ cResponse := HttpGet(cUrl + "/data", "", aHeaders)
221
+
222
+ Return cResponse
223
+
224
+ // Store credentials in SX6 parameters, environment variables,
225
+ // or a secure vault - never in source code
226
+ Static Function GetAPICredential(cParamName)
227
+ Local cValue := AllTrim(GetMV(cParamName))
228
+ Return cValue
229
+ ```
230
+
231
+ **Why it matters:** Hardcoded credentials in source code are exposed to every developer with repository access, remain in version history even after deletion, and can be extracted from compiled RPO. If the repository is compromised, all hardcoded credentials are immediately exposed. Use Protheus SX6 parameters, environment variables, or a secrets management solution instead.
232
+
233
+ ---
234
+
235
+ ## [SEC-005] Usage of TOTVS restricted/internal functions, classes, or variables
236
+
237
+ **Severity:** CRITICAL
238
+
239
+ **Description:** TOTVS maintains a list of functions, classes, and variables that are internal property. These resources are NOT documented, NOT supported, and may be altered or removed without notice. Some have their compilation blocked since release 12.1.33. Using them in custom code causes compilation failures, runtime errors, or unpredictable behavior after updates.
240
+
241
+ **What to look for:** Any call to functions or classes listed in the TOTVS restricted resources list. See `restricted-functions.md` in the protheus-reference skill for the complete list.
242
+
243
+ **Compilation BLOCKED (will not compile on 12.1.33+):**
244
+
245
+ - `StaticCall()` — use public User Functions or TLPP namespaced calls instead
246
+ - `PTInternal()` — no replacement available; redesign the logic
247
+
248
+ **Commonly found restricted functions (NOT supported, may change without notice):**
249
+
250
+ | Restricted | Alternative |
251
+ |------------|-------------|
252
+ | `PARAMBOX` | Use `Pergunte()` with SX1 or `FWInputDialog()` |
253
+ | `MsExcel` | Use `FWMsExcel` or `FWAdaptor` |
254
+ | `CriaVar` | Use `FWCriaVar()` |
255
+ | `LASTKEY` | Use specific navigation control logic |
256
+ | `SetPrvt` | Declare variables explicitly with `Private` |
257
+ | `MontaBlock` | Build code blocks directly with `{|| ... }` |
258
+ | `FWMVCROTAUTO` | Use `FWExecView()` for MVC automation |
259
+ | `FWLOOKUP` | Use `FWInputDialog()` or standard F3 lookups |
260
+ | `OPENSXS` | Tables are opened automatically by the framework |
261
+ | `APPEND FROM` | Use `RecLock` + field-by-field copy |
262
+ | `COPY TO` | Use `RecLock` + field-by-field copy |
263
+ | `LoadLayout()` | Use `FWLoadLayout()` |
264
+ | `PivotTable` | Use `FWPivotTable` |
265
+ | `StaticCall()` | Use `User Function` (public) or TLPP namespace |
266
+ | `ApOleClient` | Use `FWMsExcel` for Excel or native file operations |
267
+ | `FWAUTHUSER` | Use proper REST authentication mechanisms |
268
+ | `E_FIELD` | Use `GetSx3Cache()` or `TamSx3()` |
269
+
270
+ **Violation:**
271
+
272
+ ```advpl
273
+ User Function MyReport()
274
+ // WRONG: StaticCall is BLOCKED since 12.1.33
275
+ Local aMenu := StaticCall(MATA030, MenuDef)
276
+
277
+ // WRONG: PARAMBOX is restricted
278
+ PARAMBOX(aParams, "Filtros", , , , , , , , , .F., .F.)
279
+
280
+ // WRONG: CriaVar is restricted
281
+ Local xVal := CriaVar("A1_COD")
282
+ Return
283
+ ```
284
+
285
+ **Correct:**
286
+
287
+ ```advpl
288
+ User Function MyReport()
289
+ // CORRECT: Call public function directly
290
+ Local aMenu := U_MenuDef()
291
+
292
+ // CORRECT: Use Pergunte() with SX1 configuration
293
+ Pergunte("MYREPORT", .F.)
294
+
295
+ // CORRECT: Use FWCriaVar
296
+ Local xVal := FWCriaVar("A1_COD")
297
+ Return
298
+ ```
299
+
300
+ **Reference:** Full list at https://centraldeatendimento.totvs.com/hc/pt-br/articles/360016461772
301
+
302
+ **Why it matters:** TOTVS reserves the right to modify or remove internal functions without notice. Code that uses restricted functions will break silently after Protheus updates — or fail to compile entirely on releases 12.1.33+. The TOTVS support team does NOT provide assistance for issues caused by restricted function usage. Always use documented, supported alternatives.
@@ -0,0 +1,265 @@
1
+ ---
2
+ name: advpl-debugging
3
+ description: Use when debugging ADVPL/TLPP errors, analyzing Protheus logs, diagnosing performance issues, or troubleshooting compilation and runtime problems
4
+ ---
5
+
6
+ # ADVPL/TLPP Debugging
7
+
8
+ ## Overview
9
+
10
+ Systematic methodology for diagnosing and resolving errors in ADVPL/TLPP on TOTVS Protheus. This skill covers compilation errors, runtime failures, performance bottlenecks, database locks, log analysis, and AppServer troubleshooting.
11
+
12
+ ## When to Use
13
+
14
+ - Compilation errors (syntax, missing includes, undeclared variables)
15
+ - Runtime errors (NIL access, type mismatch, array bounds)
16
+ - Performance issues (slow queries, memory leaks, excessive loops)
17
+ - Database locks (RecLock timeouts, deadlocks, exclusive access failures)
18
+ - Log analysis (Protheus console, AppServer logs, SmartClient logs)
19
+ - AppServer issues (crash, high memory, thread exhaustion, connection problems)
20
+
21
+ ## Debug Methodology
22
+
23
+ ```dot
24
+ digraph debug_flow {
25
+ rankdir=TB;
26
+ node [shape=box, style=rounded];
27
+
28
+ A [label="Error Reported"];
29
+ B [label="Compilation Error?" shape=diamond];
30
+ C [label="Check common-errors.md\nFix syntax/includes/declarations"];
31
+ D [label="Add Logging\n(Conout / FWLogMsg)"];
32
+ E [label="Reproduce Error"];
33
+ F [label="Analyze Stack Trace\n& Log Output"];
34
+ G [label="Identify Root Cause"];
35
+ H [label="Apply Fix"];
36
+ I [label="Validate Fix\n& Remove Debug Logging"];
37
+
38
+ A -> B;
39
+ B -> C [label="Yes"];
40
+ B -> D [label="No (Runtime)"];
41
+ C -> I [label="Fixed"];
42
+ D -> E;
43
+ E -> F;
44
+ F -> G;
45
+ G -> H;
46
+ H -> I;
47
+ }
48
+ ```
49
+
50
+ **Steps:**
51
+
52
+ 1. **Error reported** - Collect the error message, stack trace, and reproduction steps
53
+ 2. **Compilation?** - If yes, consult `common-errors.md` for immediate fix
54
+ 3. **Add logging** - Insert Conout/FWLogMsg at strategic points around the failure
55
+ 4. **Reproduce** - Recreate the error in a controlled environment
56
+ 5. **Analyze stack** - Read the full stack trace, identify the failing line and function
57
+ 6. **Identify root cause** - Determine why the error occurs (data, logic, environment)
58
+ 7. **Fix** - Apply the correction, validate, and remove debug logging
59
+
60
+ ## Quick Diagnosis by Error Type
61
+
62
+ | Symptom | Likely Cause | First Check |
63
+ |---------|-------------|-------------|
64
+ | Variable does not exist | Undeclared Local or typo in name | Verify variable declaration matches usage (case-sensitive) |
65
+ | Array access out of bounds | Index exceeds `Len(aArray)` or index <= 0 | Add `Conout(Len(aArray))` before the access line |
66
+ | Type mismatch on operation | Operating on NIL or wrong type | Check `ValType()` of both operands before the line |
67
+ | File not found / Include error | Missing .ch file or wrong RPO | Verify `#Include` paths and RPO compilation |
68
+ | Lock timeout (RecLock) | Record locked by another user/thread | Check `RecLock(cAlias, .F.)` with timeout, use SM0/SMA lock monitor |
69
+ | Memory allocation error | Array growing unbounded or object leak | Check loops for `aAdd` without limit, verify `FreeObj()` calls |
70
+ | Invalid alias XXXX | WorkArea not opened or closed prematurely | Verify `DbSelectArea()` precedes the alias usage, check `Select(cAlias) > 0` |
71
+
72
+ ## Logging Tools
73
+
74
+ ### Conout (Console Output)
75
+
76
+ Simple console logging. Output appears in the Protheus AppServer console.
77
+
78
+ ```advpl
79
+ // Basic variable inspection
80
+ Conout(">>> [FATA001] cCodCli: " + cValToChar(cCodCli))
81
+ Conout(">>> [FATA001] nTotal: " + cValToChar(nTotal))
82
+ Conout(">>> [FATA001] ValType(xRet): " + ValType(xRet))
83
+
84
+ // Array inspection
85
+ Conout(">>> aItens length: " + cValToChar(Len(aItens)))
86
+ If Len(aItens) > 0
87
+ Conout(">>> aItens[1]: " + cValToChar(aItens[1]))
88
+ EndIf
89
+
90
+ // Flow tracing
91
+ Conout(">>> Entering FATA001 at " + Time())
92
+ // ... code ...
93
+ Conout(">>> Leaving FATA001 at " + Time())
94
+ ```
95
+
96
+ ### FWLogMsg (Structured Logging - Preferred)
97
+
98
+ Structured logging with severity levels. Logs are stored in the Protheus log system and can be queried.
99
+
100
+ ```advpl
101
+ // Severity levels: "INFO", "WARNING", "ERROR"
102
+ FWLogMsg("INFO", , "FATA001", "MyModule", "", 01, ;
103
+ "Processing started for client: " + cCodCli)
104
+
105
+ FWLogMsg("ERROR", , "FATA001", "MyModule", "", 02, ;
106
+ "Failed to lock record SA1. Alias: " + cAlias + ;
107
+ " RecNo: " + cValToChar(RecNo()))
108
+
109
+ FWLogMsg("WARNING", , "FATA001", "MyModule", "", 03, ;
110
+ "Slow query detected. Elapsed: " + cValToChar(nElapsed) + "s")
111
+ ```
112
+
113
+ ### ErrorBlock for Custom Stack Trace Capture
114
+
115
+ Capture and log full error details including the call stack.
116
+
117
+ ```advpl
118
+ Local oError
119
+ Local bOldError := ErrorBlock({|e| oError := e, Break(e)})
120
+
121
+ Begin Sequence
122
+
123
+ // Code that may fail
124
+ DbSelectArea("SA1")
125
+ DbSetOrder(1)
126
+ DbSeek(xFilial("SA1") + cCodCli)
127
+ cNome := SA1->A1_NOME
128
+
129
+ Recover Using oError
130
+ Conout("=== ERROR CAPTURED ===")
131
+ Conout("Description: " + oError:Description)
132
+ Conout("GenCode: " + cValToChar(oError:GenCode))
133
+ Conout("SubCode: " + cValToChar(oError:SubCode))
134
+ Conout("OsCode: " + cValToChar(oError:OsCode))
135
+ Conout("FileName: " + cValToChar(oError:FileName))
136
+ Conout("Operation: " + oError:Operation)
137
+ Conout("Args: " + cValToChar(oError:Args))
138
+ Conout("======================")
139
+
140
+ End Sequence
141
+
142
+ ErrorBlock(bOldError)
143
+ ```
144
+
145
+ ## Database Lock Diagnosis
146
+
147
+ ### RecLock with Timeout Check
148
+
149
+ Always use `.F.` (non-exclusive wait) and check the return value:
150
+
151
+ ```advpl
152
+ DbSelectArea("SD1")
153
+ DbSetOrder(1)
154
+
155
+ If DbSeek(xFilial("SD1") + cDoc + cSerie)
156
+ // Try to lock with .F. (non-blocking)
157
+ If RecLock("SD1", .F.)
158
+ SD1->D1_TOTAL := nNewTotal
159
+ MsUnlock()
160
+ Conout(">>> Record updated successfully")
161
+ Else
162
+ Conout(">>> ERROR: Could not lock SD1 RecNo " + cValToChar(RecNo()))
163
+ Conout(">>> Another user/thread may be editing this record")
164
+ // Check who is locking:
165
+ // Use Protheus Monitor (SIGAMNT) or AppServer console
166
+ EndIf
167
+ EndIf
168
+ ```
169
+
170
+ ### Common Lock Issues
171
+
172
+ | Issue | Cause | Fix |
173
+ |-------|-------|-----|
174
+ | RecLock hangs indefinitely | Using `RecLock(cAlias, .T.)` - blocks forever | Use `RecLock(cAlias, .F.)` and check return |
175
+ | Lock not released | Missing `MsUnlock()` after RecLock | Always call `MsUnlock()` after writing |
176
+ | Deadlock between threads | Two threads locking records in different order | Lock records in a consistent order, keep locks short |
177
+ | Exclusive lock failure | Another process has shared lock | Schedule exclusive operations during off-hours |
178
+
179
+ ## Performance Quick Checks
180
+
181
+ ### Wrong Index (DbSetOrder)
182
+
183
+ Using the wrong index forces a full table scan:
184
+
185
+ ```advpl
186
+ // WRONG - may use wrong index or full scan
187
+ DbSelectArea("SA1")
188
+ DbSetOrder(3) // Index 3 may not match your search key
189
+ DbSeek(xFilial("SA1") + cCodCli)
190
+
191
+ // RIGHT - verify the index matches your key
192
+ // Check SIX table for SA1 index composition
193
+ // Index 1 typically: A1_FILIAL + A1_COD + A1_LOJA
194
+ DbSelectArea("SA1")
195
+ DbSetOrder(1)
196
+ DbSeek(xFilial("SA1") + cCodCli + cLoja)
197
+ ```
198
+
199
+ ### Array Growth in Loops
200
+
201
+ Pre-allocate arrays when the size is known:
202
+
203
+ ```advpl
204
+ // SLOW - aAdd reallocates memory on every iteration
205
+ Local aResult := {}
206
+ While !Eof()
207
+ aAdd(aResult, {ALIAS->FIELD1, ALIAS->FIELD2})
208
+ DbSkip()
209
+ EndDo
210
+
211
+ // FAST - pre-allocate with aSize
212
+ Local nCount := RecCount() // or known count
213
+ Local aResult := Array(nCount)
214
+ Local nIdx := 0
215
+ While !Eof()
216
+ nIdx++
217
+ aResult[nIdx] := {ALIAS->FIELD1, ALIAS->FIELD2}
218
+ DbSkip()
219
+ EndDo
220
+ aSize(aResult, nIdx) // trim unused slots
221
+ ```
222
+
223
+ ### Embedded SQL vs ISAM
224
+
225
+ Use embedded SQL for complex queries; use ISAM for simple key lookups:
226
+
227
+ ```advpl
228
+ // ISAM - good for single-record lookup by key
229
+ DbSelectArea("SA1")
230
+ DbSetOrder(1)
231
+ If DbSeek(xFilial("SA1") + cCodCli + cLoja)
232
+ cNome := SA1->A1_NOME
233
+ EndIf
234
+
235
+ // Embedded SQL - good for filtered/aggregated queries
236
+ Local cQuery := ""
237
+ cQuery += "SELECT D1_DOC, D1_SERIE, SUM(D1_TOTAL) AS TOTAL "
238
+ cQuery += "FROM " + RetSqlName("SD1") + " SD1 "
239
+ cQuery += "WHERE D1_FILIAL = '" + xFilial("SD1") + "' "
240
+ cQuery += "AND D1_EMISSAO >= '" + DtoS(dDataIni) + "' "
241
+ cQuery += "AND SD1.D_E_L_E_T_ = ' ' "
242
+ cQuery += "GROUP BY D1_DOC, D1_SERIE"
243
+
244
+ TCQuery cQuery New Alias "QRY_TMP"
245
+ ```
246
+
247
+ See `performance-tips.md` for comprehensive optimization techniques.
248
+
249
+ ## Common Mistakes When Debugging
250
+
251
+ | Mistake | Why It Is Wrong | Better Approach |
252
+ |---------|----------------|-----------------|
253
+ | Leaving Conout in production | Floods console, impacts performance | Use FWLogMsg with severity, remove debug Conouts before deploy |
254
+ | Not saving ErrorBlock | Overwrites global error handler | Always save with `bOld := ErrorBlock(...)` and restore after |
255
+ | Using MsgAlert for debug | Blocks execution, not visible on server | Use Conout or FWLogMsg for non-interactive debugging |
256
+ | Ignoring RecLock return value | Writes to unlocked record - data corruption | Always check `If RecLock(cAlias, .F.)` |
257
+ | Not checking ValType before operations | Misses NIL values that cause runtime errors | Add `ValType(xVar) == "C"` checks before string operations |
258
+ | Debugging on production environment | Risk of data corruption or downtime | Reproduce on development/QA environment first |
259
+ | Not reading the full stack trace | Fixes symptom, not root cause | Read from bottom to top: the root cause is usually deepest in the stack |
260
+ | Hardcoding file paths in debug | Works on your machine only | Use `GetSrvProfString()` or system paths |
261
+
262
+ ## References
263
+
264
+ - `common-errors.md` - Top 50 ADVPL/TLPP errors with causes and solutions
265
+ - `performance-tips.md` - Performance optimization techniques with code examples