This commit is contained in:
Michael Dieringer 2026-06-13 22:53:17 +02:00
parent 5c13823850
commit a49823a542
4 changed files with 258 additions and 0 deletions

View file

@ -0,0 +1,81 @@
---
bc-version: [all]
domain: architecture
keywords: [naming, english, enu, variable, procedure, field, caption, translation, xliff]
technologies: [al]
countries: [w1]
application-area: [all]
---
## Description
All AL identifiers must be written in English (ENU) regardless of the language
used in conversation with the developer. Translations are handled separately
via XLIFF files — never by writing Danish, German or other language identifiers
in AL source code.
This applies to:
- Variable names
- Procedure names
- Parameter names
- Field names
- Object names (tables, codeunits, pages, enums, reports)
- Enum value names
- Local and global labels (Label data type) — both the identifier and the default text
**Captions and ToolTips** may be in the target language in the source file,
but must also be covered by XLIFF translations for all supported locales.
## Anti Pattern
```al
// WRONG: Danish identifiers
var
Kreditor: Record Vendor;
Beløb: Decimal;
AntalKilo: Decimal;
procedure BeregnTotalbeløb(Antal: Decimal; Pris: Decimal): Decimal
begin
exit(Antal * Pris);
end;
field(50101; "Indgående Mængde"; Decimal) { Caption = 'Indgående Mængde'; }
```
## Best Practice
```al
// CORRECT: English identifiers, Danish captions handled via XLIFF
var
Vendor: Record Vendor;
Amount: Decimal;
QuantityKg: Decimal;
procedure CalculateTotalAmount(Quantity: Decimal; UnitPrice: Decimal): Decimal
begin
exit(Quantity * UnitPrice);
end;
field(50101; "Inbound Quantity"; Decimal) { Caption = 'Inbound Quantity'; }
// Caption translation → da-DK XLIFF: 'Indgående Mængde'
// WRONG: Danish label identifier and text
var
BeløbFejlTxt: Label 'Beløbet må ikke være negativt';
// CORRECT: English label identifier and default text — translated via XLIFF
var
AmountMustNotBeNegativeErr: Label 'Amount must not be negative.', Comment = '%1 = Amount';
```
## Conversation vs. code
The developer may describe requirements in Danish. The agent must translate
the intent into English identifiers when writing AL code:
- "opret en variabel til beløbet" → `var Amount: Decimal;`
- "procedure der beregner lagerværdien" → `procedure CalculateInventoryValue(...)`
- "felt til indgående mængde" → `field(... ; "Inbound Quantity"; Decimal)`
Never echo Danish words from the conversation directly into AL identifiers.

View file

@ -0,0 +1,86 @@
---
bc-version: [all]
domain: architecture
keywords: [namespace, using, compile, al-language, tablerelation, variable, codeunit]
technologies: [al]
countries: [w1]
application-area: [all]
---
## Description
When an agent adds a variable referencing a BC or custom object, it must verify
the correct namespace by reading the source file of that object — not by guessing
or relying on its training data.
An AL file that "compiles" in the agent's own build may still show as red in
VS Code because the AL Language Server resolves namespaces differently.
The authoritative source for a namespace is always the object's own source file.
This rule applies to:
- `using` declarations at the top of a codeunit, table, page or enum
- Variable declarations that reference tables, codeunits, pages or enums
- `TableRelation` and `CalcFormula` references
## How to verify a namespace
Before adding a `using` statement or a variable referencing an object, the agent
must locate and read the source file for that object:
```
// Step 1: Find the source file
Glob: "**/[ObjectName].*.al" or al_symbolsearch query: "[ObjectName]"
// Step 2: Read the first line — the namespace declaration
namespace SettlementVoucher.SettlementVoucher; ← this is what to use
// Step 3: Add the using statement in the consuming file
using SettlementVoucher.SettlementVoucher;
```
If the object is a Microsoft base application object, use `al_symbolsearch` to
look up the correct namespace — do not assume it from the object name alone.
Microsoft namespaces changed significantly from BC24 onwards.
## Anti Pattern
```al
// WRONG: Guessing the namespace from the object name
using Microsoft.Purchases.Vendor; // guessed — may be wrong
using SettlementVoucher; // incomplete — missing sub-namespace
var
Vendor: Record Vendor; // missing using → red in AL Language Server
SVPost: Codeunit "SV Post"; // wrong namespace → unresolved reference
```
## Best Practice
```al
// CORRECT: Read SVPost.Codeunit.al first → find: namespace SettlementVoucher.SettlementVoucher
// CORRECT: Use al_symbolsearch to find Vendor → namespace Microsoft.Purchases.Vendor
using Microsoft.Purchases.Vendor;
using Microsoft.Finance.GeneralLedger.Ledger;
using SettlementVoucher.SettlementVoucher;
codeunit 50204 "SV Incoming Item Flow Tests"
{
var
Vendor: Record Vendor;
GLEntry: Record "G/L Entry";
SVPost: Codeunit "SV Post";
```
## Verification step before delivering code
After writing any AL file, the agent must:
1. List every `using` statement in the file
2. For each one: confirm the namespace was read from the actual source file
or looked up via `al_symbolsearch` — not assumed
3. If any namespace was assumed rather than verified, re-read the source and correct it
Never report "compiled successfully" based on a build that did not go through
the AL Language Server in VS Code. The definitive compilation result is what
VS Code shows — not the agent's internal build.

View file

@ -0,0 +1,75 @@
---
bc-version: [all]
domain: testing
keywords: [test, refactor, adapt, existing-code, green, failing, tdd]
technologies: [al]
countries: [w1]
application-area: [all]
---
## Description
When a CURABIS developer asks for a test that "must work" or "must pass",
the agent's job is to write a test that passes against the **existing production code**
— not to write an idealized test and then report that the code needs changing.
This rule applies in two distinct scenarios:
**Scenario A — New test for existing behaviour**
The production code is correct and stable. Write the test to match what the code
actually does. Read the relevant codeunits before writing assertions. If the
expected value in the story differs from what the code produces, surface the
discrepancy and ask before assuming either is wrong.
**Scenario B — Refactoring an existing test**
The test exists but fails because the production code was changed. Adapt the
test to match the new behaviour. Do not rewrite the production code to make
the old test pass unless explicitly asked to refactor production code.
## The distinction that matters
Writing a test that adapts to existing code is **not** the same as writing a
test that accepts wrong behaviour silently. If the production code contains a
bug that contradicts the business specification, flag it explicitly:
```
// ⚠️ NOTE: This assertion reflects current code behaviour.
// Business spec says 1792,00 but code currently produces 1800,00.
// Flagged for review — do not merge until resolved.
```
Never silently adjust an assertion to make a test green when the discrepancy
is a real business logic error.
## Anti Pattern
```al
// WRONG: Writing the "ideal" test without reading the production code,
// then leaving it failing and saying "the code needs to be fixed"
[THEN]
Assert.AreEqual(1792, ActualAmount, 'Total should be 1792');
// Test fails. Agent says: "You need to fix SVPost to produce 1792."
// This is not what was asked for.
```
## Best Practice
```al
// CORRECT: Read SVPost, understand what it produces, write the test to match.
// If the number is 1792 in both spec and code → assert 1792.
// If the number differs → flag it, don't silently change it.
// [GIVEN] Read SVPost.Codeunit.al and SV Test Library before writing assertions.
// [THEN] Assert what the code actually produces, verified by reading the source.
Assert.AreEqual(ExpectedAmount, ActualAmount, 'Net payout to vendor must match');
```
## Workflow when asked to write a passing test
1. Read the relevant production codeunits (SVPost, SVApplyMgt, etc.)
2. Trace the calculation path for the specific scenario
3. Derive the expected values from the code — not only from the story
4. If code and story agree → write the test with those values
5. If code and story disagree → write the test with the code's values AND add
a clearly visible `// ⚠️ NOTE` comment explaining the discrepancy
6. Never leave a test failing when the task was to write a passing test