Pular para o conteúdo

Diagnósticos que indicam o próximo passo

N0 é mecânico; N1 precisa de dados ou escolha fechada; N2 exige decisão de negócio. O nível é diferente da severidade (warning/error) e do modo de correção.

100 resultados

SIL1001N1

A module has exactly five projects whose names and paths match the module and layer.

{
  "severity": "warning",
  "scope": "module",
  "source": "specs/01",
  "fix": {
    "description": "Create or rename the project as src/Modules/<Module>/Sil.Modules.<Module>.<Layer>/Sil.Modules.<Module>.<Layer>.csproj; 'dotnet builder new module <Module> --dry-run' lists the five expected projects.",
    "kind": "manual"
  },
  "examples": {
    "bad": "src/Modules/Yard/Yard.Core/Yard.Core.csproj",
    "good": "src/Modules/Yard/Sil.Modules.Yard.Domain/Sil.Modules.Yard.Domain.csproj"
  }
}
SIL1002N0

Request handlers are internal sealed, with one handler per request type; the code fix makes the handler internal sealed.

{
  "severity": "warning",
  "scope": "handler",
  "source": "specs/06",
  "fix": {
    "description": "Apply the code fix 'Make the handler internal sealed'; split a handler that handles several request types.",
    "kind": "codefix"
  },
  "examples": {
    "bad": "public class InsertDockHandler : IRequestHandler<InsertDockCommand, Guid>",
    "good": "internal sealed class InsertDockHandler : IRequestHandler<InsertDockCommand, Guid>"
  }
}
SIL1003N2

Common/runtime cannot reference concrete modules.

{
  "severity": "warning",
  "scope": "project",
  "source": "specs/01",
  "fix": {
    "description": "Remove the reference from the runtime/Common project; move the shared abstraction into the runtime or keep the code in the module.",
    "kind": "manual"
  },
  "examples": {
    "bad": "<ProjectReference Include=\"../../Modules/Dock/Sil.Modules.Dock.Domain/Sil.Modules.Dock.Domain.csproj\" /> in a Common project",
    "good": "A src/Common project that references only framework and Sil.Builder.* packages"
  }
}
SIL1004N2

References respect the layer graph; cross-module access requires explicit approval.

{
  "severity": "warning",
  "scope": "project",
  "source": "specs/01; PAR-02",
  "fix": {
    "description": "Remove the reference or route it through the allowed edge (ApiControllers -> Application -> Domain/Contracts, Infrastructure -> Domain/Application); a cross-module edge needs PAR-02 approval.",
    "kind": "manual"
  },
  "examples": {
    "bad": "Sil.Modules.Dock.Application -> Sil.Modules.Yard.Infrastructure",
    "good": "Sil.Modules.Dock.Application -> Sil.Modules.Dock.Domain"
  }
}
SIL1006N1

Discontinued SdkUtils utilities and packages are forbidden, including aliases and qualified names.

{
  "severity": "error",
  "scope": "code/package",
  "source": "D0.2; ADR-BLD-0001",
  "fix": {
    "description": "Replace the discontinued utility with a supported Sil.SdkMono, Sil.Builder.Runtime or .NET API and remove the package.",
    "kind": "manual"
  },
  "examples": {
    "bad": "using SdkUtils; var id = SdkUtils.Ids.NewId();",
    "good": "var id = SilId.New(timeProvider);"
  }
}
SIL1104N1

Values must be passed as SQL parameters, never interpolated into SQL.

{
  "severity": "warning",
  "scope": "SQL call",
  "source": "specs/06",
  "fix": {
    "description": "Pass every value as a SQL parameter; keep only trusted identifiers from the ListDefinition in the SQL text.",
    "kind": "manual"
  },
  "examples": {
    "bad": "connection.QueryAsync<DockRow>($\"select * from dock.doca where doc_id = '{id}'\")",
    "good": "connection.QueryAsync<DockRow>(\"select * from dock.doca where doc_id = @id\", new { id })"
  }
}
SIL1105N0

Use the injected clock for instants; the code fix uses the only TimeProvider in scope.

{
  "severity": "warning",
  "scope": "code",
  "source": "D0.13",
  "fix": {
    "description": "Apply the code fix 'Use the injected clock'; inject TimeProvider when the type has none.",
    "kind": "codefix"
  },
  "examples": {
    "bad": "var now = DateTimeOffset.UtcNow;",
    "good": "var now = timeProvider.GetUtcNow();"
  }
}
SIL1106N0

Use UUID v7 for entity identities. The code fix replaces Guid.NewGuid() with Guid.CreateVersion7() only at identity sites (Guid members, locals, parameters or methods named Id/*Id); `fix --rule SIL1106` covers Guid Id initializers in net10 Domain projects. Tokens and nonces keep NewGuid after review.

{
  "severity": "warning",
  "scope": "code",
  "source": "D0.9",
  "fix": {
    "description": "Apply the code fix 'Use Guid.CreateVersion7()' at identity sites ('dotnet builder fix --rule SIL1106' rewrites Guid Id initializers of Domain projects); keep NewGuid for tokens and nonces after review.",
    "kind": "codefix"
  },
  "examples": {
    "bad": "public Guid Id { get; init; } = Guid.NewGuid();",
    "good": "public Guid Id { get; init; } = Guid.CreateVersion7();"
  }
}
SIL1108N1

No Environment.GetEnvironmentVariable or literal SIL_* configuration keys outside *Settings/*Options classes.

{
  "severity": "warning",
  "scope": "code",
  "source": "specs/06; M8",
  "fix": {
    "description": "Bind the setting to a *Options/*Settings class through IOptions<T> and read it there.",
    "kind": "manual"
  },
  "examples": {
    "bad": "var rows = Environment.GetEnvironmentVariable(\"SIL_DOCK_MAX_ROWS\");",
    "good": "public sealed class DockOptions { public int MaxRows { get; init; } } // bound from configuration"
  }
}
SIL1201N0

Return or propagate failed Results; do not discard them. The code fix adds return when the member type accepts the Result.

{
  "severity": "warning",
  "scope": "code",
  "source": "D0.5",
  "fix": {
    "description": "Apply the code fix 'Return the failed Result', or propagate the failure explicitly.",
    "kind": "codefix"
  },
  "examples": {
    "bad": "if (!found) Result.Failure(DockErrors.NotFound);",
    "good": "if (!found) return Result.Failure(DockErrors.NotFound);"
  }
}
SIL1204N2

Never send exception text to clients; personal data of audited entities needs [MaskInLog] or [NotPersonalData(reason)].

{
  "severity": "warning",
  "scope": "code",
  "source": "specs/06; M13",
  "fix": {
    "description": "Return a SilError instead of exception text; mark personal data of audited entities with [MaskInLog] or [NotPersonalData(reason)].",
    "kind": "manual"
  },
  "examples": {
    "bad": "return Results.Problem(exception.Message);",
    "good": "return Result.Failure(DockErrors.Unavailable);"
  }
}
SIL1206N0

No Console.Write/WriteLine in non-test projects and no HttpRequest, HttpContext or header objects in logs (by argument type, or a destructured {@Request}/{@Context}/{@Headers} hole whose value is untyped); the code fix removes a standalone console statement.

{
  "severity": "warning",
  "scope": "code",
  "source": "specs/06; M13",
  "fix": {
    "description": "Apply the code fix 'Remove the console statement' and log through ILogger without request, context or header objects.",
    "kind": "codefix"
  },
  "examples": {
    "bad": "Console.WriteLine($\"Dock {id} created\"); logger.LogInformation(\"{@Request}\", request);",
    "good": "logger.LogInformation(\"Dock {DockId} created.\", id);"
  }
}
SIL1301N1

Route templates are <area>/v<n>/<resource> in lowercase kebab-case; action templates hold only parameters and kebab-case literals.

{
  "severity": "warning",
  "scope": "route",
  "source": "specs/10; D0.12",
  "fix": {
    "description": "Write the route as <area>/v<n>/<resource> in lowercase kebab-case and keep only parameters and kebab-case literals in action templates.",
    "kind": "manual"
  },
  "examples": {
    "bad": "[SilClientRoute(\"Dock/Docas\")]",
    "good": "[SilClientRoute(\"dock/v1/docas\")]"
  }
}
SIL1302N1

Controller actions return IResult or Task<IResult> produced by the runtime result helpers.

{
  "severity": "warning",
  "scope": "controller",
  "source": "specs/10",
  "fix": {
    "description": "Return IResult (or Task<IResult>) from the runtime result helpers (ToHttpResult, ToCreatedHttpResult, ToPageHttpResult).",
    "kind": "manual"
  },
  "examples": {
    "bad": "public async Task<GetDockDTO?> Get(Guid guid) => await service.FindAsync(guid);",
    "good": "public async Task<IResult> Get(Guid guid, CancellationToken token) => (await service.GetAsync(guid, token)).ToHttpResult();"
  }
}
SIL1303N1

Every public controller action declares a summary ([EndpointSummary] or XML <summary>).

{
  "severity": "warning",
  "scope": "controller",
  "source": "specs/10",
  "fix": {
    "description": "Add [EndpointSummary(\"<what the action does>\")] or an XML <summary> to the action.",
    "kind": "manual"
  },
  "examples": {
    "bad": "[HttpGet(\"{guid:guid}\")] public Task<IResult> Get(...)",
    "good": "[EndpointSummary(\"Returns one dock.\")] [HttpGet(\"{guid:guid}\")] public Task<IResult> Get(...)"
  }
}
SIL1305N0

Controllers declare publics with [SilClientRoute]; [Route] with a literal public prefix is forbidden. The code fix applies only when the controller already declares client/, service/ and internal/ for the same resource, which [SilClientRoute] replicates exactly.

{
  "severity": "warning",
  "scope": "route",
  "source": "specs/10; BDN-003.b",
  "fix": {
    "description": "Apply the code fix 'Use [SilClientRoute]' when client/, service/ and internal/ routes exist for the resource; otherwise declare the publics with [SilClientRoute] by hand.",
    "kind": "codefix"
  },
  "examples": {
    "bad": "[Route(\"client/dock/v1/docas\")]",
    "good": "[SilClientRoute(\"dock/v1/docas\")]"
  }
}
SIL1306N1

Controllers never build responses with Ok(), BadRequest(), NotFound(), StatusCode(), Content(), ObjectResult or anonymous objects.

{
  "severity": "warning",
  "scope": "controller",
  "source": "specs/10",
  "fix": {
    "description": "Build the response with the runtime result helpers instead of ControllerBase helpers or anonymous objects.",
    "kind": "manual"
  },
  "examples": {
    "bad": "return Ok(new { data = dock });",
    "good": "return result.ToHttpResult();"
  }
}
SIL1307N1

The result helper matches the HTTP verb: POST creates, PUT/PATCH/DELETE answer 204, GET answers one object or a list.

{
  "severity": "warning",
  "scope": "controller",
  "source": "specs/10",
  "fix": {
    "description": "Use the helper of the verb: ToCreatedHttpResult for POST, ToHttpResult on a valueless Result (204) for PUT/PATCH/DELETE, ToHttpResult/ToPageHttpResult for GET.",
    "kind": "manual"
  },
  "examples": {
    "bad": "[HttpPost] ... => (await handler.HandleAsync(new(data), token)).ToHttpResult();",
    "good": "[HttpPost] ... => (await handler.HandleAsync(new(data), token)).ToCreatedHttpResult();"
  }
}
SIL1308N0

Contract properties declare JSON names; the code fix adds the JsonPropertyName the serializer already writes (camelCase, or sil_builder.json_naming_policy = none), so the wire name is unchanged (D0.24).

{
  "severity": "warning",
  "scope": "contract",
  "source": "specs/10; D0.24",
  "fix": {
    "description": "Apply the code fix 'Add JsonPropertyName'; it writes the name the serializer already uses, so the wire stays the same.",
    "kind": "codefix"
  },
  "examples": {
    "bad": "public string Name { get; init; } = \"\";",
    "good": "[JsonPropertyName(\"nome\")] public string Name { get; init; } = \"\";"
  }
}
SIL1309N0

Route parameters are {guid:guid} or {<resource>Guid:guid}; the code fix renames the parameter and the bound Guid argument.

{
  "severity": "warning",
  "scope": "route",
  "source": "specs/10; D0.12",
  "fix": {
    "description": "Apply the code fix 'Rename the route parameter' to {guid:guid} (or {<resource>Guid:guid} for a sub-level).",
    "kind": "codefix"
  },
  "examples": {
    "bad": "[HttpGet(\"{id}\")] public Task<IResult> Get(Guid id, ...)",
    "good": "[HttpGet(\"{guid:guid}\")] public Task<IResult> Get(Guid guid, ...)"
  }
}
SIL1404N1

SilError messages follow the Sil norm (EN/pt-BR, <=200 characters, uppercase start, final period, no jargon, generic 5xx, no shared language-carrying interpolation) and definitive codes are unique per call site (X0000001 may repeat until registration).

{
  "severity": "warning",
  "scope": "code",
  "source": "specs/06; M1; L8; D0.7",
  "fix": {
    "description": "Rewrite the messages by the Sil norm: English error_message citing the JSON key, pt-BR display_message, up to 200 characters, uppercase start, final period, generic text for 5xx and a distinct definitive code per call site; X0000001 may repeat until registration.",
    "kind": "manual"
  },
  "examples": {
    "bad": "new SilError(\"E1\", \"nome obrigatorio\", \"nome obrigatorio\", 400)",
    "good": "new SilError(\"DOCK_DOCK_INSERT_NAME_REQUIRED\", \"Field 'nome' is required.\", \"O campo 'nome' é obrigatório.\", 400)"
  }
}
SIL1801N1

Tests assert error codes instead of bare IsSuccess and never read C# source files.

{
  "severity": "warning",
  "scope": "test",
  "source": "specs/06; M19",
  "fix": {
    "description": "Assert the error code (and messages) of the failure; read behavior through the API, never C# source files.",
    "kind": "manual"
  },
  "examples": {
    "bad": "Assert.False(result.IsSuccess); var code = File.ReadAllText(\"DockHandlers.cs\");",
    "good": "Assert.Equal(\"DOCK_DOCK_INSERT_NAME_REQUIRED\", result.Error!.Code);"
  }
}
SIL1601N2

Generated files retain their recorded hashes.

{
  "severity": "error",
  "scope": "manifest",
  "source": "BDN-012.a",
  "fix": {
    "description": "Move the manual change into a business region or into the feature spec, restore the generated text and regenerate; 'spec sync <feature>' lists the divergence. After a merge that kept one side of .builder/manifest.json, 'manifest rebuild' records the files that are still generator output.",
    "kind": "manual"
  },
  "examples": {
    "bad": "Editing the generated validator of a // <sil-generated .../> file outside any business region.",
    "good": "// <sil-business id=\"dock-insert-rules\">\nif (await repository.IsBlockedAsync(data.Name, token)) return Result.Failure(DockErrors.NameBlocked);\n// </sil-business>"
  }
}
SIL9001N1

Suppressions require a justified GAP identifier.

{
  "severity": "warning",
  "scope": "code",
  "source": "specs/06",
  "fix": {
    "description": "Add the GAP identifier and justification to the suppression (#pragma warning disable SIL1106 // GAP-12 reason) or remove it.",
    "kind": "manual"
  },
  "examples": {
    "bad": "#pragma warning disable SIL1106",
    "good": "#pragma warning disable SIL1106 // GAP-12 legacy tokens keep random GUIDs"
  }
}
BLD2001N1

Migration name, task uniqueness, header and UP/DOWN follow the SQL convention.

{
  "severity": "error",
  "scope": "migration",
  "source": "BDN-009.a",
  "fix": {
    "args": [
      "new",
      "migration",
      "<TASK-ID>",
      "<description>",
      "--author",
      "<name>",
      "--link",
      "<task-url>",
      "--date",
      "<yyyy-MM-dd>"
    ],
    "command": "dotnet builder new migration '<TASK-ID>' '<description>' --author '<name>' --link '<task-url>' --date '<yyyy-MM-dd>'",
    "description": "Generate the migration with the correct name, header and UP/DOWN blocks, move the reviewed SQL into its UP block and delete the misnamed file.",
    "kind": "command"
  },
  "examples": {
    "bad": ".migrations/add_dock_field.sql without header or UP/DOWN",
    "good": ".migrations/V20261002_BLD-42.sql with -- Author/Date/Task/Description, -- UP with BEGIN; ... COMMIT; and a commented -- DOWN"
  }
}
BLD2002N2

Destructive DDL requires an explicit reviewed exception.

{
  "severity": "warning",
  "scope": "migration",
  "source": "BDN-009.a",
  "fix": {
    "description": "Review the destructive DDL; keep it only with '-- Exception: GAP-<id> <reason>' in the header, or replace it with expand-contract steps.",
    "kind": "manual"
  },
  "examples": {
    "bad": "ALTER TABLE dock.doca DROP COLUMN doc_name;",
    "good": "-- Exception: GAP-31 column replaced by doc_nome in V20261001_BLD-40\nALTER TABLE dock.doca DROP COLUMN doc_name;"
  }
}
BLD2003N1

Catalog errors have a registered (S/X), provisional X0000001 or legacy symbolic code, unique origins and definitive codes, and distinct bilingual messages.

{
  "severity": "error",
  "scope": "snapshot",
  "source": "D0.7; PAR-07; feature-pipeline §2",
  "fix": {
    "description": "Keep each origin unique and use X0000001 until registration, or a unique definitive code (S/X plus 7 digits) with distinct, norm-compliant English and pt-BR messages in .builder/errors.json.",
    "kind": "manual"
  },
  "examples": {
    "bad": "{ \"code\": \"1\", \"origin\": \"\", \"message\": \"Nome obrigatório\", \"displayMessage\": \"Nome obrigatório\" }",
    "good": "{ \"code\": \"S0000001\", \"origin\": \"Dock.Insert.NameRequired\", \"message\": \"Field 'nome' is required.\", \"displayMessage\": \"O campo 'nome' é obrigatório.\" }"
  }
}
BLD2004N1

Published migrations are immutable against the specified base commit.

{
  "severity": "error",
  "scope": "migration",
  "source": "BDN-009.a",
  "fix": {
    "args": [
      "new",
      "migration",
      "<TASK-ID>",
      "<description>",
      "--author",
      "<name>",
      "--link",
      "<task-url>",
      "--date",
      "<yyyy-MM-dd>"
    ],
    "command": "dotnet builder new migration '<TASK-ID>' '<description>' --author '<name>' --link '<task-url>' --date '<yyyy-MM-dd>'",
    "description": "Restore the published migration from the base commit and put the change in a new task migration.",
    "kind": "command"
  },
  "examples": {
    "bad": "Editing .migrations/V20261002_BLD-42.sql after it reached the base branch",
    "good": "A new .migrations/V20261004_BLD-43.sql that alters what V20261002_BLD-42.sql created"
  }
}
BLD2005N1

Messages in the local error snapshot follow the Sil message norm of SIL1404.

{
  "severity": "warning",
  "scope": "snapshot",
  "source": "specs/06; M1; L8",
  "fix": {
    "description": "Rewrite the snapshot messages by the Sil norm (English error_message, pt-BR display_message, up to 200 characters, uppercase start, final period, generic 5xx).",
    "kind": "manual"
  },
  "examples": {
    "bad": "\"message\": \"nome obrigatório\", \"displayMessage\": \"nome obrigatório\"",
    "good": "\"message\": \"Field 'nome' is required.\", \"displayMessage\": \"O campo 'nome' é obrigatório.\""
  }
}
BLD2006N2

A business region that the spec no longer generates is empty; one holding code stops spec apply until the code moves elsewhere or the rule or criterion returns to the spec.

{
  "severity": "error",
  "scope": "generation",
  "source": "feature-pipeline §3.1; BDN-012.a",
  "fix": {
    "description": "Move the code of the orphan business region into a region the spec still generates or into a hand-written file, or return the rule or acceptance criterion to the spec; then apply again.",
    "kind": "manual"
  },
  "examples": {
    "bad": "Removing RN-01 from builder.rules while its business region still holds the check",
    "good": "rules: [{ id: RN-01, hook: NameNotBlocked, on: [insert] }] kept in the spec while // <sil-business id=\"dock-rule-name-not-blocked\"> holds code"
  }
}
BLD2007N1

spec sync finds no drift between the spec, the generated files, the schema snapshot and manual edits; drift exits 1 and nothing is written. spec plan|apply stop on an orphan file (this feature's header, no longer generated).

{
  "severity": "error",
  "scope": "generation",
  "source": "feature-pipeline §5; ADR-BLD-0003",
  "fix": {
    "args": [
      "spec",
      "apply",
      "<feature>",
      "--dry-run"
    ],
    "command": "dotnet builder spec apply '<feature>' --dry-run",
    "description": "Move manual edits into business regions or into the spec, delete orphan files by hand (apply never deletes) and regenerate.",
    "kind": "command"
  },
  "examples": {
    "bad": "A generated DockHandlers.cs edited outside its regions, or DockValidator.cs left behind after the field was removed",
    "good": "spec sync features/dock/2026-10-03-dock-docas exits 0 after spec apply"
  }
}
BLD2008N2

Required references of a module form no cycle and reach applied features, so the first record can be created; the generated database tests seed a target without insert through the module DbContext.

{
  "severity": "error",
  "scope": "generation",
  "source": "feature-pipeline §6",
  "fix": {
    "description": "Make one reference of the cycle optional, or apply the referenced feature before this one (it does not need to publish insert).",
    "kind": "manual"
  },
  "examples": {
    "bad": "Berth.DockId required -> Dock and Dock.MainBerthId required -> Berth",
    "good": "Berth.DockId required -> Dock (Dock applied first, with or without insert, and no required reference back)"
  }
}
BLD2009N1

A regenerated location keeps its registrationKey; spec plan|apply warn when its registration identity changes, as after renaming a field's C# name.

{
  "severity": "warning",
  "scope": "generation",
  "source": "D0.7; feature-pipeline §2",
  "fix": {
    "description": "Keep the registration identity: revert the hand edit and rename with 'dotnet builder refactor rename-field <feature> <Field> <NewName>', which pins the old stem in codeStem, or add codeStem with the old stem yourself; otherwise reconcile the new registrationKey with the error registry.",
    "kind": "manual"
  },
  "examples": {
    "bad": "Renaming Name to Title by hand silently turns DOCK_DOCK_INSERT_NAME_REQUIRED into DOCK_DOCK_INSERT_TITLE_REQUIRED",
    "good": "- { name: Title, json: nome, codeStem: NAME, ... } keeps DOCK_DOCK_INSERT_NAME_REQUIRED"
  }
}
BLD4001N1

OpenAPI operations have resolved local references, typed error/create schemas and valid parameters.

{
  "severity": "error",
  "scope": "OpenAPI file",
  "source": "specs/10",
  "fix": {
    "description": "Complete the OpenAPI operation: summary, tags, a unique operationId, the error envelope on 4xx/5xx, required path parameters and object_id on 201.",
    "kind": "manual"
  },
  "examples": {
    "bad": "\"post\": { \"responses\": { \"201\": {} } }",
    "good": "\"post\": { \"summary\": \"Creates a dock.\", \"tags\": [\"Docks\"], \"operationId\": \"insertDock\", \"responses\": { \"201\": { \"$ref\": \"#/components/responses/Created\" }, \"400\": { \"$ref\": \"#/components/responses/Error\" } } }"
  }
}
BLD4002N0

Artifacts derived from the feature specs (.builder/openapi.json, .builder/hoppscotch.json, .builder/permissions.json, .builder/proposals/permissions-seed.sql and each module's permission constants) equal what the specs produce: none stale, and none missing while the specs publish an API.

{
  "severity": "error",
  "scope": "derived artifact",
  "source": "feature-pipeline §3, §5; L12; L13",
  "fix": {
    "args": [
      "spec",
      "apply",
      "<feature>"
    ],
    "command": "dotnet builder spec apply '<feature>'",
    "description": "Regenerate the derived artifacts from the specs: 'spec apply <feature>' rewrites all of them in the feature's plan; 'contract export --from-specs' rewrites only the OpenAPI document and 'contract hoppscotch' only the collection.",
    "kind": "command"
  },
  "examples": {
    "bad": "A field added to the spec by hand, or .builder/openapi.json edited by hand, while the committed contract and collection still describe the old surface",
    "good": "spec apply features/dock/2026-10-03-dock-docas, then .builder/openapi.json, .builder/hoppscotch.json and .builder/permissions.json match the specs (check reports no BLD4002)"
  }
}
BLD4003N1

No two features of the workspace serve the same path and method; spec apply, contract export --from-specs and check stop on such a pair, since the host would map it twice and the derived contract could describe only one.

{
  "severity": "error",
  "scope": "derived artifact",
  "source": "feature-pipeline §3.3; L12",
  "fix": {
    "description": "Give each feature its own builder.api.resource (<area>/v<n>/<resource>, unique in the workspace); when a feature moved to another resource in its spec, apply it before the feature that takes its old resource.",
    "kind": "manual"
  },
  "examples": {
    "bad": "features/yard/... with resource stock/v1/itens, which features/stock/2026-10-04-stock-itens already serves at /client/stock/v1/itens",
    "good": "features/yard/... with resource yard/v1/patios beside features/stock/... with resource stock/v1/itens"
  }
}
BLD4004N2

Every applied feature (schema snapshot under .builder/schema) has its spec with a builder block; without it, its generated code still serves its endpoints and the derived artifacts keep describing it.

{
  "severity": "error",
  "scope": "derived artifact",
  "source": "feature-pipeline §3.3; L12; L13",
  "fix": {
    "description": "Restore the spec, or remove the feature by hand: delete its schema snapshot and the files whose first line is its sil-generated header, remove their manifest entries, drop its table in a reviewed migration and apply another feature.",
    "kind": "manual"
  },
  "examples": {
    "bad": "Deleting .plintrix/features/stock/2026-10-04-stock-itens.md and leaving .builder/schema/stock/item.json, ItemController.cs and the item routes in .builder/openapi.json",
    "good": ".plintrix/features/stock/2026-10-04-stock-itens.md kept while .builder/schema/stock/item.json and ItemController.cs exist"
  }
}
BLD4005N1

No derived artifact is left behind that no feature produces any more (the last feature of the workspace, or of the module for its permission constants, stopped publishing builder.api); spec apply never deletes files.

{
  "severity": "error",
  "scope": "derived artifact",
  "source": "feature-pipeline §3.3; L12; L13",
  "fix": {
    "description": "Delete the artifact and its entry in .builder/manifest.json (spec apply never deletes files), or publish builder.api again and apply the feature.",
    "kind": "manual"
  },
  "examples": {
    "bad": ".builder/openapi.json and StockPermissions.cs left after the last Stock feature dropped builder.api",
    "good": "No .builder/openapi.json in a workspace whose features publish no builder.api"
  }
}
BLD7001N1

add platform-client reads an OpenAPI 3.0 or 3.1 document in JSON (the openapi.json the platform publishes).

{
  "severity": "error",
  "scope": "platform client",
  "source": "L14; contract §5.2",
  "fix": {
    "description": "Pass the OpenAPI 3.x JSON document the platform publishes (openapi.json); convert YAML or Swagger 2.0 to OpenAPI 3 JSON first.",
    "kind": "manual"
  },
  "examples": {
    "bad": "dotnet builder add platform-client Organizations --openapi contracts/platform.yaml --tag Organizations",
    "good": "dotnet builder add platform-client Organizations --openapi contracts/platform-openapi.json --tag Organizations"
  }
}
BLD7002N1

The --tag of add platform-client selects at least one operation of the document.

{
  "severity": "error",
  "scope": "platform client",
  "source": "L14; contract §5.2",
  "fix": {
    "args": [
      "add",
      "platform-client",
      "<Name>",
      "--openapi",
      "<openapi.json>",
      "--tag",
      "<tag>"
    ],
    "command": "dotnet builder add platform-client '<Name>' --openapi '<openapi.json>' --tag '<tag>'",
    "description": "Pass --tag with a tag the document declares on its operations; the diagnostic lists them.",
    "kind": "command"
  },
  "examples": {
    "bad": "--tag organizations when the document tags the operations Organizations",
    "good": "--tag Organizations, a tag of GET /service/platform/v1/organizations"
  }
}
BLD7003N1

Every selected operation has a unique operationId, and operationIds, parameters, properties, schemas and enum values map to distinct C# identifiers.

{
  "severity": "error",
  "scope": "platform client",
  "source": "L14; contract §5.2",
  "fix": {
    "description": "Ask the platform for unique operationIds and for names that differ beyond case and separators (parameters, properties, schemas, enum values); the method name comes from the operationId.",
    "kind": "manual"
  },
  "examples": {
    "bad": "operationId: get-organization and operationId: getOrganization, which both become GetOrganizationAsync",
    "good": "operationId: listOrganizations and operationId: getOrganization (ListOrganizationsAsync, GetOrganizationAsync)"
  }
}
BLD7004N2

The selected operations use only the supported OpenAPI subset: JSON bodies, path/query/header parameters, local $ref, objects, arrays, maps, scalars, string enums, allOf of objects and oneOf/anyOf with a discriminator; recursion only through an object schema.

{
  "severity": "error",
  "scope": "platform client",
  "source": "L14; contract §5.2",
  "fix": {
    "description": "Keep the operation out of the generated client: call it with hand-written code over HttpClient (multipart, files, text bodies), or ask the platform to publish it within the supported subset (a discriminator for oneOf/anyOf, local $ref, JSON bodies).",
    "kind": "manual"
  },
  "examples": {
    "bad": "oneOf: [OrganizationCreated, OrganizationRemoved] without a discriminator, or a multipart/form-data upload",
    "good": "oneOf: [EmailNotification, SmsNotification] with discriminator: { propertyName: kind }"
  }
}
BLD7005N1

add platform-client adds its projects to the workspace solution: one .slnx at the root, or the one --solution names (an XML solution inside the workspace).

{
  "severity": "error",
  "scope": "platform client",
  "source": "L14",
  "fix": {
    "args": [
      "add",
      "platform-client",
      "<Name>",
      "--openapi",
      "<openapi.json>",
      "--tag",
      "<tag>",
      "--solution",
      "<file.slnx>"
    ],
    "command": "dotnet builder add platform-client '<Name>' --openapi '<openapi.json>' --tag '<tag>' --solution '<file.slnx>'",
    "description": "Pass --solution with the .slnx of the workspace that should list the client projects (an XML solution; dotnet sln migrate writes one), or keep a single .slnx at the workspace root.",
    "kind": "command"
  },
  "examples": {
    "bad": "A workspace with Sil.Yard.slnx and Legacy.slnx at the root and no --solution",
    "good": "dotnet builder add platform-client Organizations --openapi platform.json --tag Organizations --solution Sil.Yard.slnx"
  }
}
BLD7006N2

The generated identity hook forwards the incoming Authorization header until BDN-003.c defines the service identity of backends that call the platform.

{
  "severity": "info",
  "scope": "platform client",
  "source": "L14; BDN-003.c; ADR-BLD-0004",
  "fix": {
    "description": "Decide the service identity with BDN-003.c and register your own I<Name>Identity (service account, token exchange) before Add<Name>PlatformClient; until then the default forwards the incoming Authorization header.",
    "kind": "manual"
  },
  "examples": {
    "bad": "Copying a user token into a background job's platform call, where no incoming request carries Authorization",
    "good": "services.AddSingleton<IOrganizationsIdentity, ServiceAccountIdentity>(); services.AddOrganizationsPlatformClient(builder.Configuration);"
  }
}
BLD7010N0

A codemod (refactor rename-entity|rename-field|move-route|change-public) starts from the applied state: the spec equals the builder block its schema snapshot recorded.

{
  "severity": "error",
  "scope": "codemod",
  "source": "L17; feature-pipeline §5",
  "fix": {
    "args": [
      "spec",
      "apply",
      "<feature>"
    ],
    "command": "dotnet builder spec apply '<feature>'",
    "description": "Apply the pending spec edit (or revert it) so the spec equals its applied state, then run the codemod; it plans from the applied state and changes only what it renames.",
    "kind": "command"
  },
  "examples": {
    "bad": "A field added to the spec without spec apply, then refactor rename-entity on the same spec",
    "good": "spec sync features/dock/2026-10-03-dock-docas exits 0, then refactor rename-field features/dock/2026-10-03-dock-docas Name Title"
  }
}
BLD7011N1

A codemod changes something and its new name, JSON name, column, resource or publics do not collide with the feature or its module, nor its new table with the table of any other feature (specs and schema snapshots of every module) or the schema's audit_log.

{
  "severity": "error",
  "scope": "codemod",
  "source": "L17",
  "fix": {
    "description": "Pass a name, JSON name, column, resource or set of publics that changes something and is free in the feature and its module, and a table that no other feature of any module uses (spec or .builder/schema snapshot) and that is not the schema's audit_log.",
    "kind": "manual"
  },
  "examples": {
    "bad": "refactor rename-field features/dock/2026-10-03-dock-docas Name Active, when Active already exists; refactor rename-entity ... Berth --table dock.portao, the table of the Gate feature",
    "good": "refactor rename-field features/dock/2026-10-03-dock-docas Name Title"
  }
}
BLD7012N2

refactor rename-entity renames an entity no other feature of the module references (target); a referenced entity is renamed by hand across the features.

{
  "severity": "error",
  "scope": "codemod",
  "source": "L17; feature-pipeline §1.2 (BLD5019)",
  "fix": {
    "description": "Rename the entity by hand across the features that reference it (each referencing field's target, then spec apply of each feature with a reviewed migration), or keep the C# name and change only the labels.",
    "kind": "manual"
  },
  "examples": {
    "bad": "refactor rename-entity Warehouse Depot while features/stock/2026-10-04-stock-itens has { target: Warehouse }",
    "good": "refactor rename-entity on an entity no other feature of the module targets"
  }
}
BLD7013N2

refactor rename-entity --table renames the table within its schema; moving it to another schema needs a reviewed migration.

{
  "severity": "error",
  "scope": "codemod",
  "source": "L17; BDN-009.a",
  "fix": {
    "description": "Keep the schema in --table (rename within it); move the table to another schema with a reviewed migration and a spec edit.",
    "kind": "manual"
  },
  "examples": {
    "bad": "refactor rename-entity features/dock/2026-10-03-dock-docas Berth --table yard.berco",
    "good": "refactor rename-entity features/dock/2026-10-03-dock-docas Berth --table dock.berco"
  }
}
BLD7014N2

A hand-written name the codemod renamed without binding it to the renamed symbol (or could not rename), and a renamed table or column it replaced inside a string (hand-written SQL), is reviewed by a person.

{
  "severity": "warning",
  "scope": "codemod",
  "source": "L17; D0.3",
  "fix": {
    "description": "Open the file at the line, confirm the identifier named the renamed member and the string is SQL over the renamed table (revert the rename otherwise), or rename it by hand when the codemod could not; restore the project so the codemod binds every reference next time.",
    "kind": "manual"
  },
  "examples": {
    "bad": "settings.Name renamed to settings.Title although settings is not a renamed DTO",
    "good": "dto.Title, where dto is a GetDockDTO and Name became Title; \"SELECT doc_titulo FROM dock.doca\" after --column doc_titulo"
  }
}
BLD7015N2

A codemod that changes the published contract (move-route, change-public, a new JSON name, operationIds) reports each breaking change of contract diff; the consumers agree before the merge.

{
  "severity": "warning",
  "scope": "codemod",
  "source": "L17; L12; feature-pipeline §3.3",
  "fix": {
    "description": "Agree the contract change with every consumer (clients, Hoppscotch collections, the front) before merging, or keep the old route, public or JSON name; release notes list the change.",
    "kind": "manual"
  },
  "examples": {
    "bad": "change-public dropping client while the front still calls /client/dock/v1/docas",
    "good": "move-route announced to the consumers, with the new /client/yard/v1/docas routes in the release notes"
  }
}
BLD7016N2

A codemod deletes a generated file only when no hand-written code (whole files of the module, its tests and the host, or business regions) still references what it declares.

{
  "severity": "error",
  "scope": "codemod",
  "source": "L17",
  "fix": {
    "description": "Point each listed reference at code that stays (the remaining controller, another type of the module) or remove it, then run the codemod again; the codemod never deletes code people still use.",
    "kind": "manual"
  },
  "examples": {
    "bad": "refactor change-public ... backoffice while Program.cs still has typeof(DockController), the client controller the codemod deletes",
    "good": "builder.Services.AddControllers().AddApplicationPart(typeof(DockBackofficeController).Assembly); before refactor change-public ... backoffice"
  }
}
BLD5001N1

The feature has a YAML front-matter between '---' fences and the YAML is valid (line/column reported).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Start the file with a '---' line, the YAML front-matter and a closing '---' line; 'dotnet builder new feature' writes a complete skeleton.",
    "kind": "manual"
  },
  "examples": {
    "bad": "# Docas\nid: features/dock/2026-10-03-dock-docas",
    "good": "---\nid: features/dock/2026-10-03-dock-docas\nlayer: feature\n---\n# Docas"
  }
}
BLD5002N1

The front-matter follows schemas/feature.schema.json: required keys, types, enums, patterns, and no unknown key inside builder; JSON values expand to at most 10,000 nodes through aliases.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Fix the key named by the JSON path to match schemas/feature.schema.json (required keys, types, enums, patterns, no unknown keys inside builder).",
    "kind": "manual"
  },
  "examples": {
    "bad": "fields:\n  - { name: Name, json: Nome, type: varchar, size: 100 }",
    "good": "fields:\n  - { name: Name, json: nome, type: string, max: 100 }"
  }
}
BLD5003N1

The id equals the file path below .plintrix/ without .md.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Set id to the file path below .plintrix/ without .md, or move the file to match the id.",
    "kind": "manual"
  },
  "examples": {
    "bad": ".plintrix/features/dock/2026-10-03-dock-docas.md with id: features/dock/docas",
    "good": ".plintrix/features/dock/2026-10-03-dock-docas.md with id: features/dock/2026-10-03-dock-docas"
  }
}
BLD5004N1

layer is feature and status is a C4 status (draft, ready, in-progress, shipped, archived).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Set 'layer: feature' and a C4 status (draft, ready, in-progress, shipped, archived).",
    "kind": "manual"
  },
  "examples": {
    "bad": "layer: product\nstatus: done",
    "good": "layer: feature\nstatus: draft"
  }
}
BLD5005N1

extends/uses reference C0-C3 blocks with valid SemVer ranges; features never reference features (§5.7).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Reference only C0-C3 blocks (constitution, platform/..., domain/..., products/..., presets/...) with a valid SemVer range.",
    "kind": "manual"
  },
  "examples": {
    "bad": "uses:\n  - features/dock/2026-10-01-dock-base@>=1",
    "good": "uses:\n  platform:\n    - platform/api-rules@0.x"
  }
}
BLD5006N1

The feature extends the constitution.

{
  "severity": "warning",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Add 'extends: [constitution@<range>]' with the constitution version of the repository.",
    "kind": "manual"
  },
  "examples": {
    "bad": "extends: []",
    "good": "extends:\n  - constitution@0.x"
  }
}
BLD5010N1

builder.schema is a schema this builder reads (1).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Use builder schema 1, or update dotnet-builder to a version that reads the declared schema.",
    "kind": "manual"
  },
  "examples": {
    "bad": "builder:\n  schema: 3",
    "good": "builder:\n  schema: 1"
  }
}
BLD5011N1

Field C# names are neither reserved nor repeated; JSON names are unique and not id; columns do not collide; schema, table and columns are not PostgreSQL reserved words; database names fit 63 bytes; field and entity names do not collapse into the same error code.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Rename the field: C# names must not repeat or reuse the runtime members (Id, OrganizationId, CreatedAt, ...); JSON names and columns must be unique and not id.",
    "kind": "manual"
  },
  "examples": {
    "bad": "- { name: Id, json: id, type: guid }",
    "good": "- { name: DockCode, json: codigo, type: string, max: 20 }"
  }
}
BLD5012N1

Field type and attributes agree (max, precision, values, target, trim, default); enum values give distinct C# constants; an external entity (entity.external) is bigint-identity, tenant none, audit none, softDelete false, without api, rules, acceptance, unique or reference, and every field has column.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Make type and attributes agree: max on string, precision on decimal, values on enum, target on reference, trim only on text, a default of the field type. An external entity (entity.external) is read-only: key bigint-identity, tenant none, audit none, softDelete false, column on every field, and no api, rules, acceptance, unique or reference.",
    "kind": "manual"
  },
  "examples": {
    "bad": "- { name: Kind, json: tipo, type: string, values: [A, B] }",
    "good": "- { name: Kind, json: tipo, type: enum, values: [A, B] }"
  }
}
BLD5013N1

unique: organization requires a tenant-owned entity.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Use 'unique: global' on an entity with 'tenant: none', or make the entity tenant-owned.",
    "kind": "manual"
  },
  "examples": {
    "bad": "entity: { tenant: none }\nfields:\n  - { name: Name, json: nome, type: string, max: 100, unique: organization }",
    "good": "entity: { tenant: organization }\nfields:\n  - { name: Name, json: nome, type: string, max: 100, unique: organization }"
  }
}
BLD5014N1

List filters, sort, defaultSort, fullSearch and status cite existing fields of a compatible type and operator; null applies only to nullable fields.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Point list filters, sort, defaultSort, fullSearch and status at existing fields of a compatible type and operator.",
    "kind": "manual"
  },
  "examples": {
    "bad": "list:\n  filters:\n    - { field: Active, ops: [like] }\n  status: Name",
    "good": "list:\n  filters:\n    - { field: Name, ops: [eq, like] }\n  status: Active"
  }
}
BLD5015N0

builder.api.list requires the list operation.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "args": [
      "add",
      "endpoint",
      "<feature>",
      "list"
    ],
    "command": "dotnet builder add endpoint '<feature>' list",
    "description": "Publish the list operation, or remove builder.api.list.",
    "kind": "command"
  },
  "examples": {
    "bad": "api:\n  operations: [get]\n  list: { sort: [Name] }",
    "good": "api:\n  operations: [get, list]\n  list: { sort: [Name] }"
  }
}
BLD5016N1

Permission action ranges match their operation (get/list 10-19, insert 20-29, update 30-39, delete 40-49).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Use the permission code whose action range matches the operation: get/list 10-19, insert 20-29, update 30-39, delete 40-49.",
    "kind": "manual"
  },
  "examples": {
    "bad": "permissions: { insert: TMS.DOC.cadast.docaxx.10 }",
    "good": "permissions: { insert: TMS.DOC.cadast.docaxx.20 }"
  }
}
BLD5017N1

Published operations declare a permission or permissions.exempt.

{
  "severity": "warning",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "args": [
      "add",
      "permission",
      "<feature>",
      "<operation>",
      "<PRD.MOD.funcio.objeto.AC>"
    ],
    "command": "dotnet builder add permission '<feature>' '<operation>' '<PRD.MOD.funcio.objeto.AC>'",
    "description": "Declare the Sil permission code of each published operation, or justify the absence in permissions.exempt.",
    "kind": "command"
  },
  "examples": {
    "bad": "api:\n  operations: [get, list]   # no permissions and no exempt",
    "good": "permissions: { get: TMS.DOC.cadast.docaxx.10, list: TMS.DOC.cadast.docaxx.11 }"
  }
}
BLD5018N1

The resource is <area>/v<n>/<resource>, without the public, and unique within the workspace (its host maps every module).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Write the resource as <area>/v<n>/<resource> without the public, unique within the workspace.",
    "kind": "manual"
  },
  "examples": {
    "bad": "resource: client/dock/docas",
    "good": "resource: dock/v1/docas"
  }
}
BLD5019N1

Reference targets are entities of the same module (schema 1); a global entity does not reference a tenant-owned one; a numeric tenant names a global bigint-identity organization of the module, generated or external; only entity.organization points to an external entity.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Point target at an entity of the same module; store a foreign id as a guid field validated by a business rule (N2) otherwise. A numeric tenant names a global bigint-identity organization of the module, which may be external (entity.external, such as base.organizacao); only entity.organization points to an external entity.",
    "kind": "manual"
  },
  "examples": {
    "bad": "- { name: Vehicle, json: veiculo, type: reference, target: Fleet.Vehicle }",
    "good": "- { name: Dock, json: doca, type: reference, target: Dock }"
  }
}
BLD5020N1

errors[].key overrides a generated or rule error; rules[].error has its own key and an override with en and pt text; a generated error whose default text exceeds 200 characters has an override.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Override only generated or rule errors, give every rules[].error an override with en and pt text, and shorten default texts above 200 characters with an override.",
    "kind": "manual"
  },
  "examples": {
    "bad": "errors:\n  - { key: Whatever, en: Something failed. }",
    "good": "errors:\n  - { key: NameBlocked, rule: RN-02, en: Dock name is blocked., pt: O nome da doca está bloqueado. }"
  }
}
BLD5021N1

acceptance[].expect.error is a generated error or the runtime NotFound.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Use a generated error key (such as NameRequired) or the runtime NotFound in acceptance[].expect.error.",
    "kind": "manual"
  },
  "examples": {
    "bad": "expect: { status: 400, error: NAME_REQUIRED }",
    "good": "expect: { status: 400, error: NameRequired }"
  }
}
BLD5030N2

template: v2 has the required sections (Data model with persistencia, API surface with api).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Add the missing template v2 section in its order ('dotnet builder new feature' shows the skeleton) and describe it.",
    "kind": "manual"
  },
  "examples": {
    "bad": "A v2 feature with superficie: [api] and no '## API surface' section",
    "good": "## 5. Business rules\n\n| # | Regra | Descrição |"
  }
}
BLD5031N1

Open questions is not empty ('Nenhuma.' when there is none).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Write the open questions, or 'Nenhuma.' when there is none.",
    "kind": "manual"
  },
  "examples": {
    "bad": "## 10. Open questions\n",
    "good": "## 10. Open questions\n\nNenhuma."
  }
}
BLD5032N1

superficie and the builder block agree (api with builder.api, persistencia with builder.entity.table).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Make superficie and the block agree: api with builder.api, persistencia with builder.entity.table.",
    "kind": "manual"
  },
  "examples": {
    "bad": "superficie: [api]\nbuilder:\n  entity: { ... }   # no api",
    "good": "superficie: [api, persistencia]\nbuilder:\n  api: { resource: dock/v1/docas, ... }"
  }
}
BLD5033N2

errors[].rule and rules[].id have an RN-NN row in the Business rules table.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Add the RN-NN row to the Business rules table, or fix the id in errors[].rule / rules[].id.",
    "kind": "manual"
  },
  "examples": {
    "bad": "rules: [{ id: RN-09, hook: NameBlocked, on: [insert] }] with no RN-09 row",
    "good": "| RN-02 | Nome bloqueado | ... |  and  rules: [{ id: RN-02, hook: NameBlocked, on: [insert] }]"
  }
}
BLD5034N2

acceptance[].id has a CA-NN row in the Acceptance criteria table.

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Add the CA-NN row to the Acceptance criteria table, or fix the id in builder.acceptance.",
    "kind": "manual"
  },
  "examples": {
    "bad": "acceptance: [{ id: CA-07, ... }] with no CA-07 row",
    "good": "| CA-01 | ... |  and  acceptance: [{ id: CA-01, ... }]"
  }
}
BLD5035N2

Every CA-NN row has a builder.acceptance entry; otherwise a red test is generated (N2).

{
  "severity": "warning",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Add a builder.acceptance entry when the criterion has an executable form; otherwise implement the red test that the generator emits in a business region.",
    "kind": "manual"
  },
  "examples": {
    "bad": "| CA-03 | ... | with no executable entry and no test",
    "good": "| CA-03 | ... |  and  acceptance: [{ id: CA-03, request: { method: PUT, path: \"{guid}\" }, expect: { status: 400, error: NotFound } }]"
  }
}
BLD5036N1

A feature without the builder key is checked only for the Plintrix and template rules; nothing is generated.

{
  "severity": "info",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003",
  "fix": {
    "description": "Add the builder block from the prose when the feature is to be generated (closed data validated by the schema).",
    "kind": "manual"
  },
  "examples": {
    "bad": "A feature meant for generation without a builder key",
    "good": "builder:\n  schema: 1\n  module: Dock\n  entity: { ... }\n  fields: [ ... ]"
  }
}
BLD5040N1

Table, columns, types, nullability, defaults, constraints, indexes and comments of the spec match the given database (spec lint --db runs the comparison of db diff).

{
  "severity": "error",
  "scope": "feature spec",
  "source": "feature-pipeline §1.2; ADR-BLD-0003; L11",
  "fix": {
    "description": "Align the spec and the database (table, columns, types, nullability, defaults, constraints, indexes, comments); 'dotnet builder db diff <feature> --connection <cs>' details each difference, and a destructive change needs a reviewed migration.",
    "kind": "manual"
  },
  "examples": {
    "bad": "max: 100 in the spec and varchar(60) in the database",
    "good": "max: 100 in the spec and varchar(100) in dock.doca.doc_nome"
  }
}
BLD6001N1

db verify creates and drops its disposable database (sil_verify_<random>) on the server of --connection, so the role needs CREATEDB; nothing else on the server is touched.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; Q2; D0.29",
  "fix": {
    "description": "Run db verify with a role that may create databases (ALTER ROLE <role> CREATEDB, or the CI service account); db verify drops its database at the end and touches nothing else.",
    "kind": "manual"
  },
  "examples": {
    "bad": "dotnet builder db verify --connection with the backend's application role, which cannot create databases",
    "good": "dotnet builder db verify --connection 'Host=localhost;Username=postgres;Password=...' (a role with CREATEDB)"
  }
}
BLD6002N1

The schema-only baseline (--baseline) applies on an empty database before the migrations.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; D0.29; PAR-08",
  "fix": {
    "description": "Regenerate the baseline with pg_dump --schema-only --no-owner from the approved server version (D0.29) so it applies on an empty database; until PAR-08 approves one, run db verify without --baseline.",
    "kind": "manual"
  },
  "examples": {
    "bad": "--baseline with a data dump, or a dump that needs roles and extensions the server lacks",
    "good": "--baseline baseline/schema.sql written by pg_dump --schema-only --no-owner of the approved PostgreSQL version"
  }
}
BLD6003N2

Every .migrations/V*.sql applies, in the generator's order (date, then task), on the database built from the baseline and the earlier migrations, each in a session of its own (as psql -f runs it) that commits every transaction it opens.

{
  "severity": "error",
  "scope": "migration",
  "source": "L9; BDN-009.a",
  "fix": {
    "description": "Correct the failing statement, or end the UP section with the COMMIT of its BEGIN; a published migration is immutable (BLD2004), so the fix goes in a new task migration, while an unpublished one can still be edited.",
    "kind": "manual"
  },
  "examples": {
    "bad": "ALTER TABLE dock.doca ADD COLUMN ... in a migration that runs before the one that creates dock.doca",
    "good": "V20261003_BLD-1.sql creates dock.doca and V20261005_BLD-2.sql alters it"
  }
}
BLD6004N1

Migrations are idempotent: a second pass of every migration over the same database succeeds (IF NOT EXISTS and guarded changes).

{
  "severity": "error",
  "scope": "migration",
  "source": "L9; BDN-009.a",
  "fix": {
    "description": "Guard the statement so it can run twice: CREATE ... IF NOT EXISTS, ADD COLUMN IF NOT EXISTS, DROP ... IF EXISTS, or a DO block that checks pg_constraint before ADD CONSTRAINT.",
    "kind": "manual"
  },
  "examples": {
    "bad": "CREATE TABLE dock.patio (pat_id uuid NOT NULL);",
    "good": "CREATE TABLE IF NOT EXISTS dock.patio (pat_id uuid NOT NULL);"
  }
}
BLD6005N1

Every table a spec or schema snapshot declares exists in the database.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "args": [
      "spec",
      "apply",
      "<feature>",
      "--dry-run"
    ],
    "command": "dotnet builder spec apply '<feature>' --dry-run",
    "description": "Apply the spec so its migration creates the table (spec apply with --task, --author and --link), or point builder.entity.table at the existing table.",
    "kind": "command"
  },
  "examples": {
    "bad": "builder.entity.table: dock.docas while the migrations create dock.doca",
    "good": "builder.entity.table: dock.doca and V20261003_BLD-1.sql creating dock.doca"
  }
}
BLD6006N2

Every table of a schema the specs own is declared by a spec or a schema snapshot.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "args": [
      "new",
      "feature",
      "<Module>",
      "<slug>",
      "--entity",
      "<Name>",
      "--from-db",
      "<schema.table>",
      "--connection",
      "<connection>"
    ],
    "command": "dotnet builder new feature '<Module>' '<slug>' --entity '<Name>' --from-db '<schema.table>' --connection '<connection>'",
    "description": "Describe the table in a feature spec generated from it (then review its fields), or drop it in a reviewed migration (BLD2002).",
    "kind": "command"
  },
  "examples": {
    "bad": "A dock.patio table created by hand in a migration, with no spec",
    "good": "Every table of schema dock comes from a feature of module Dock"
  }
}
BLD6007N1

Every column of the spec (standard columns and fields) exists in its table.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "description": "Apply the spec so its migration adds the column (ADD COLUMN IF NOT EXISTS), or correct the field's json or column to the existing column.",
    "kind": "manual"
  },
  "examples": {
    "bad": "- { name: Name, json: nome, ... } while the table has dock.doca.doc_name",
    "good": "- { name: Name, json: nome, ... } and the column dock.doca.doc_nome"
  }
}
BLD6008N2

Every column of the table is a standard column or a field of the spec.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "description": "Declare the column as a field of the spec ('dotnet builder add field <feature> <Name>:<type> --json <json>'), or drop it in a reviewed migration (BLD2002).",
    "kind": "manual"
  },
  "examples": {
    "bad": "dock.doca.doc_codigo added by a hand-written migration and absent from the spec",
    "good": "dock.doca.doc_codigo declared as - { name: Code, json: codigo, type: string, max: 20 }"
  }
}
BLD6009N1

Column types match the spec, including varchar length and numeric precision and scale.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "description": "Make the type agree: change max, precision or type in the spec (spec apply widens automatically), or alter the column in a reviewed migration (narrowing is never automatic, BLD2002).",
    "kind": "manual"
  },
  "examples": {
    "bad": "max: 100 and dock.doca.doc_nome varchar(60)",
    "good": "max: 100 and dock.doca.doc_nome varchar(100)"
  }
}
BLD6010N1

Nullability matches the spec: a required field or a field with a default is NOT NULL; the others accept NULL.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "description": "Make nullability agree: required or a default makes the column NOT NULL; change the spec, or SET/DROP NOT NULL in a reviewed migration (backfill first).",
    "kind": "manual"
  },
  "examples": {
    "bad": "required: true and doc_nome varchar(100) NULL",
    "good": "required: true and doc_nome varchar(100) NOT NULL"
  }
}
BLD6011N1

Column defaults match the spec defaults.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "description": "Make the default agree: change default in the spec (spec apply sets it), or ALTER COLUMN ... SET DEFAULT in a reviewed migration.",
    "kind": "manual"
  },
  "examples": {
    "bad": "default: true and doc_ativo boolean NOT NULL DEFAULT false",
    "good": "default: true and doc_ativo boolean NOT NULL DEFAULT true"
  }
}
BLD6012N1

Constraints follow the conventions: pk_<table> on <p>_id, ck_<table>_<column> with the enum values (D0.26), fk_<table>_<column> to the target id; the table has no constraint outside the spec.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2; D0.26",
  "fix": {
    "description": "Create or rename the constraint as the convention names it (pk_<table>, ck_<table>_<column>, fk_<table>_<column>) with the spec's definition in a reviewed migration; a constraint outside the spec moves into it or goes.",
    "kind": "manual"
  },
  "examples": {
    "bad": "CONSTRAINT item_tipo_check CHECK (itm_tipo IN ('RAW'))",
    "good": "CONSTRAINT ck_item_itm_tipo CHECK (itm_tipo IN ('RAW', 'FINISHED'))"
  }
}
BLD6013N1

Indexes follow the conventions: uk_<table>_<column> or uk_<table>_org_<column> unique and ix_<table>_orgid, on the spec's columns; the table has no unique index outside the spec.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "description": "Create or rename the index as the convention names it (uk_<table>_<column>, uk_<table>_org_<column>, ix_<table>_orgid) on the spec's columns in a reviewed migration.",
    "kind": "manual"
  },
  "examples": {
    "bad": "A tenant-owned dock.doca without ix_doca_orgid",
    "good": "CREATE INDEX IF NOT EXISTS ix_doca_orgid ON dock.doca (doc_orgid);"
  }
}
BLD6014N1

Unique indexes of soft-deleted tables are partial: WHERE <p>_deldat IS NULL.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "description": "Recreate the unique index as partial, CREATE UNIQUE INDEX IF NOT EXISTS uk_... ON ... (...) WHERE <p>_deldat IS NULL, and drop the full one in the same reviewed migration.",
    "kind": "manual"
  },
  "examples": {
    "bad": "CREATE UNIQUE INDEX uk_doca_org_doc_nome ON dock.doca (doc_orgid, doc_nome);",
    "good": "CREATE UNIQUE INDEX IF NOT EXISTS uk_doca_org_doc_nome ON dock.doca (doc_orgid, doc_nome) WHERE doc_deldat IS NULL;"
  }
}
BLD6015N1

Table and column comments match the spec (COMMENT ON from labels and descriptions).

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2; D0.26",
  "fix": {
    "description": "Write COMMENT ON TABLE/COLUMN with the spec's text in a reviewed migration, or change the description or labels in the spec.",
    "kind": "manual"
  },
  "examples": {
    "bad": "dock.doca.doc_nome without a comment while the spec describes it",
    "good": "COMMENT ON COLUMN dock.doca.doc_nome IS 'Nome da doca.'; with description: Nome da doca."
  }
}
BLD6016N1

<schema>.audit_log exists with the runtime's columns, check and index when an entity of the schema has audit: log.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; L11; feature-pipeline §3.2",
  "fix": {
    "description": "Create <schema>.audit_log as the generated migration does (CREATE TABLE IF NOT EXISTS with id, organization_id, table_name, record_id, operation, changes, user_id and at), or set audit to stamps or none in the spec.",
    "kind": "manual"
  },
  "examples": {
    "bad": "audit: log and no dock.audit_log, so the first insert fails",
    "good": "audit: log and dock.audit_log created by V20261003_BLD-1.sql"
  }
}
BLD6017N2

Every statement the generated query repositories run prepares and explains on the migrated database: the read by id and the list with each declared filter operator, sort, full search, status and page.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; D0.3; D0.14",
  "fix": {
    "description": "Make the list definition and the table agree: the failing column comes from a spec field (json, column, type) or from a hand-edited migration; fix the spec and apply it, or fix the schema in a reviewed migration.",
    "kind": "manual"
  },
  "examples": {
    "bad": "column: doc_titulo in the spec while the migration created doc_nome, so every list fails with 42703 at runtime",
    "good": "SELECT t.doc_nome ... FROM dock.doca t WHERE t.doc_orgid = @organization_id prepares on the migrated database"
  }
}
BLD6018N1

A feature generated from a table (new feature --from-db) states what needs human input: what the database cannot tell (English C# names, pt-BR labels, gender and resource), columns without a builder field type, and every difference db diff would report between the inferred spec and its table (a CHECK that is no enum, unique indexes the spec cannot express, names off the conventions, default expressions).

{
  "severity": "warning",
  "scope": "feature spec",
  "source": "L11; specs/05",
  "fix": {
    "description": "Fill in what the database cannot tell: rename the fields to their English C# names, confirm the pt-BR labels, gender and resource, add the unmapped columns by hand, and settle each reported difference (a rule hook, or a reviewed migration that brings the table to the conventions); then run spec lint and db diff.",
    "kind": "manual"
  },
  "examples": {
    "bad": "- { name: Nome, json: nome, type: string, max: 100, required: true } kept as inferred",
    "good": "- { name: Name, json: nome, type: string, max: 100, required: true }"
  }
}
BLD6019N1

A spec and its schema snapshot describe the same table; a spec edited after its last apply needs spec apply (and its migration) before db verify proves it.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; feature-pipeline §3.2",
  "fix": {
    "args": [
      "spec",
      "apply",
      "<feature>",
      "--dry-run"
    ],
    "command": "dotnet builder spec apply '<feature>' --dry-run",
    "description": "Apply the spec (spec apply with --task, --author and --link) so its migration and snapshot follow it, or revert the spec edit.",
    "kind": "command"
  },
  "examples": {
    "bad": "A field added to the spec without spec apply, so no migration creates its column",
    "good": "spec sync features/dock/2026-10-03-dock-docas exits 0 before db verify"
  }
}
BLD6020N2

Every schema snapshot (.builder/schema/**) is readable: unknown shapes (a 'check' that is not a list of values, a bad partitionBy or primaryKey) are reported instead of leaving the table undeclared.

{
  "severity": "error",
  "scope": "database",
  "source": "L9; feature-pipeline §3.2",
  "fix": {
    "description": "Correct the snapshot to a shape the builder reads: 'check' is a list of accepted values, 'checkExpression' is the SQL of a numeric or comparison CHECK, 'primaryKey' lists the key columns (the partition column last) and 'partitionBy' is { type: range|list|hash, column }.",
    "kind": "manual"
  },
  "examples": {
    "bad": "{ \"name\": \"lot_total\", \"check\": \"lot_total >= 1 AND lot_total <= 500\" }, a text where the list of values goes, which dropped the whole snapshot",
    "good": "{ \"name\": \"lot_total\", \"type\": \"integer\", \"nullable\": false, \"checkExpression\": \"lot_total >= 1 AND lot_total <= 500\" }"
  }
}
SIL1103N2

Tenant filtering must be proved for EF, Dapper and joins.

{
  "severity": "warning",
  "scope": "database",
  "source": "D0.14; PAR-08",
  "fix": {
    "description": "Prove tenant filtering for EF, Dapper and joins with two-organization integration tests against PostgreSQL.",
    "kind": "manual"
  },
  "examples": {
    "bad": "select ... from dock.doca where doc_id = @id",
    "good": "select ... from dock.doca where doc_orgid = @organizationId and doc_deldat is null"
  }
}
BLD3001N2

HTTP trust/public conformance needs an approved audience matrix.

{
  "severity": "warning",
  "scope": "HTTP",
  "source": "PAR-03",
  "fix": {
    "description": "Conformance waits for the approved public/audience matrix (PAR-03); review the routes and audiences by hand meanwhile.",
    "kind": "manual"
  },
  "examples": {
    "bad": "/internal reachable with an end-user token and no origin check",
    "good": "/client routes require ssp:client and an organization claim"
  }
}
BLD3002N2

Compatibility must be measured against approved package/schema combinations.

{
  "severity": "warning",
  "scope": "compatibility",
  "source": "PAR-04/08",
  "fix": {
    "description": "Compatibility waits for the approved package/schema matrix (PAR-04/08); review package and schema changes by hand meanwhile.",
    "kind": "manual"
  },
  "examples": {
    "bad": "Bumping Sil.Builder.Runtime without running the compatibility matrix",
    "good": "Upgrade measured against the approved Sil.Builder.Runtime/schema combinations"
  }
}
Janela do terminal
dotnet builder explain SIL1106
dotnet builder fix --rule SIL1106 --dry-run

O catálogo fornece a origem da decisão, o escopo, o fix e exemplos quando disponíveis. Diagnósticos concretos podem especializar a correção com os dados da feature. Revise o preview antes de aplicar.

A exceção de 07/10/2026 permite Sil.SdkMono e suas dependências Common em SIL1007; SdkUtils e Common isolado continuam bloqueados. BLD2003 e SIL1404 aceitam X0000001 repetido como placeholder até o cadastro, sem dispensar a validação de origens e mensagens. No error_message, SIL1404 e BLD2005 ignoram termos de contrato em pt-BR (chave ou valor entre aspas ou crases e constantes em maiúsculas como EM_ANALISE ou RASCUNHO, ATIVO), tanto na verificação de idioma quanto na de jargão; texto natural em português continua acusado.