Fix multiline function call style violations

Expand mixed inline/multiline function calls so each argument
is on its own line, matching the one-argument-per-line rule.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-03-17 15:34:01 +01:00
parent 532347fcda
commit 16b966b8fb
28 changed files with 203 additions and 83 deletions

View File

@@ -346,7 +346,9 @@ func (w *CompletionCertificateWorker) handleCertFailure(
scope coredata.Scoper,
processingError error,
) error {
w.logger.ErrorCtx(ctx, "certificate worker failure",
w.logger.ErrorCtx(
ctx,
"certificate worker failure",
log.Error(processingError),
log.String("signature_id", signature.ID.String()),
)

View File

@@ -289,7 +289,9 @@ func (w *SealingWorker) failSignature(
) error {
scope := coredata.NewScopeFromObjectID(signature.ID)
w.logger.ErrorCtx(ctx, "sealing worker failure",
w.logger.ErrorCtx(
ctx,
"sealing worker failure",
log.Error(processingError),
log.String("signature_id", signature.ID.String()),
)

View File

@@ -332,8 +332,11 @@ func TestFileCategories(t *testing.T) {
err := v.Validate("test"+otherTC.validExt, otherTC.validMimeType, 1024)
if err == nil {
t.Errorf("Expected error when validating %s file with %s validator, but got none",
otherTC.category, tc.category)
t.Errorf(
"Expected error when validating %s file with %s validator, but got none",
otherTC.category,
tc.category,
)
}
}
})

View File

@@ -250,7 +250,8 @@ func (s *OrganizationService) UpdateMempership(
scope := coredata.NewScopeFromObjectID(organizationID)
membership := coredata.Membership{}
if err := s.pg.WithTx(ctx,
if err := s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
if err := membership.LoadByID(ctx, tx, scope, membershipID); err != nil {

View File

@@ -21,7 +21,9 @@ import (
func TestEvaluator_Evaluate_AllowDecision(t *testing.T) {
evaluator := NewEvaluator()
policy := NewPolicy("test", "Test Policy",
policy := NewPolicy(
"test",
"Test Policy",
Allow("iam:identity:get", "iam:identity:update"),
)
@@ -68,7 +70,9 @@ func TestEvaluator_Evaluate_AllowDecision(t *testing.T) {
func TestEvaluator_Evaluate_DenyDecision(t *testing.T) {
evaluator := NewEvaluator()
policy := NewPolicy("test", "Test Policy",
policy := NewPolicy(
"test",
"Test Policy",
Allow("iam:*:*"),
Deny("iam:organization:delete").WithSID("deny-org-delete"),
)
@@ -112,10 +116,14 @@ func TestEvaluator_Evaluate_DenyWinsOverAllow(t *testing.T) {
evaluator := NewEvaluator()
// Two policies: one allows, one denies the same action
allowPolicy := NewPolicy("allow", "Allow Policy",
allowPolicy := NewPolicy(
"allow",
"Allow Policy",
Allow("iam:organization:delete"),
)
denyPolicy := NewPolicy("deny", "Deny Policy",
denyPolicy := NewPolicy(
"deny",
"Deny Policy",
Deny("iam:organization:delete"),
)
@@ -147,7 +155,9 @@ func TestEvaluator_Evaluate_WithConditions(t *testing.T) {
evaluator := NewEvaluator()
// Policy that only allows users to update their own identity
selfManagePolicy := NewPolicy("self-manage", "Self Manage",
selfManagePolicy := NewPolicy(
"self-manage",
"Self Manage",
Allow("iam:identity:update").
When(Equals("principal.id", "resource.id")),
)
@@ -194,7 +204,9 @@ func TestEvaluator_Evaluate_MultipleConditions(t *testing.T) {
evaluator := NewEvaluator()
// Policy that requires both conditions to be met
policy := NewPolicy("test", "Test",
policy := NewPolicy(
"test",
"Test",
Allow("documents:document:update").
When(
Equals("principal.id", "resource.owner_id"),
@@ -358,7 +370,9 @@ func TestEvaluator_Evaluate_NilPolicies(t *testing.T) {
func TestEvaluator_Evaluate_MatchedStatementAndPolicy(t *testing.T) {
evaluator := NewEvaluator()
policy := NewPolicy("test-policy", "Test Policy",
policy := NewPolicy(
"test-policy",
"Test Policy",
Allow("iam:identity:get").WithSID("allow-get"),
Deny("iam:identity:delete").WithSID("deny-delete"),
)

View File

@@ -22,24 +22,32 @@ import (
func Example_definingPolicies() {
// Define a viewer policy - can read everything
viewerPolicy := policy.NewPolicy("viewer", "Viewer Policy",
viewerPolicy := policy.NewPolicy(
"viewer",
"Viewer Policy",
policy.Allow("*:*:read", "*:*:list"),
).WithDescription("Read-only access to all resources")
// Define an admin policy - can do everything except delete organization
adminPolicy := policy.NewPolicy("admin", "Admin Policy",
adminPolicy := policy.NewPolicy(
"admin",
"Admin Policy",
policy.Allow("*"),
policy.Deny("iam:organization:delete"),
).WithDescription("Full access except organization deletion")
// Define a self-manage policy - users can manage their own identity
selfManagePolicy := policy.NewPolicy("self-manage", "Self Management Policy",
selfManagePolicy := policy.NewPolicy(
"self-manage",
"Self Management Policy",
policy.Allow("iam:identity:get", "iam:identity:update").
When(policy.Equals("principal.id", "resource.id")),
).WithDescription("Users can view and update their own identity")
// Define a document owner policy - owners can do anything to their documents
documentOwnerPolicy := policy.NewPolicy("doc-owner", "Document Owner Policy",
documentOwnerPolicy := policy.NewPolicy(
"doc-owner",
"Document Owner Policy",
policy.Allow("documents:document:*").
When(policy.Equals("principal.id", "resource.owner_id")),
).WithDescription("Document owners have full control over their documents")
@@ -60,11 +68,15 @@ func Example_evaluatingPolicies() {
evaluator := policy.NewEvaluator()
// Define policies
viewerPolicy := policy.NewPolicy("viewer", "Viewer",
viewerPolicy := policy.NewPolicy(
"viewer",
"Viewer",
policy.Allow("*:*:read", "*:*:list"),
)
adminPolicy := policy.NewPolicy("admin", "Admin",
adminPolicy := policy.NewPolicy(
"admin",
"Admin",
policy.Allow("*"),
policy.Deny("iam:organization:delete").WithSID("prevent-org-deletion"),
)
@@ -119,7 +131,9 @@ func Example_conditionBasedAccess() {
evaluator := policy.NewEvaluator()
// Policy: users can only update their own profile
selfManagePolicy := policy.NewPolicy("self-manage", "Self Management",
selfManagePolicy := policy.NewPolicy(
"self-manage",
"Self Management",
policy.Allow("iam:identity:update").
When(policy.Equals("principal.id", "resource.id")),
)

View File

@@ -115,12 +115,16 @@ func (v *SAMLDomainVerifier) checkUnverifiedDomains(ctx context.Context) error {
if err := v.tryVerifyDomain(ctx, config.ID); err != nil {
if errors.Is(err, errDomainTXTRecordNotFound) || errors.Is(err, errDomainTXTRecordMismatch) {
v.logger.InfoCtx(ctx, "domain verification pending",
v.logger.InfoCtx(
ctx,
"domain verification pending",
log.String("config_id", config.ID.String()),
log.Error(err),
)
} else {
v.logger.ErrorCtx(ctx, "cannot verify domain",
v.logger.ErrorCtx(
ctx,
"cannot verify domain",
log.String("config_id", config.ID.String()),
log.Error(err),
)
@@ -160,7 +164,9 @@ func (v *SAMLDomainVerifier) tryVerifyDomain(ctx context.Context, configID gid.G
return err
}
v.logger.InfoCtx(ctx, "domain verified",
v.logger.InfoCtx(
ctx,
"domain verified",
log.String("config_id", config.ID.String()),
)

View File

@@ -107,7 +107,9 @@ func NewBridgeRunner(
// Run starts the runner loop that processes SCIM bridges.
func (r *BridgeRunner) Run(ctx context.Context) error {
r.logger.InfoCtx(ctx, "starting SCIM bridge runner",
r.logger.InfoCtx(
ctx,
"starting SCIM bridge runner",
log.Duration("poll_interval", r.cfg.PollInterval),
log.Duration("sync_interval", r.cfg.Interval),
log.Duration("sync_timeout", r.cfg.SyncTimeout),

View File

@@ -85,7 +85,9 @@ func (r *BridgeRunner) transitionToSuccess(
bridge.UpdatedAt = now
if err := bridge.Update(ctx, conn, scope); err != nil {
logger.ErrorCtx(ctx, "cannot update bridge after successful sync",
logger.ErrorCtx(
ctx,
"cannot update bridge after successful sync",
log.Error(err),
)
return err
@@ -94,14 +96,18 @@ func (r *BridgeRunner) transitionToSuccess(
if connector != nil {
connector.UpdatedAt = now
if err := connector.Update(ctx, conn, scope, r.encryptionKey); err != nil {
logger.WarnCtx(ctx, "cannot persist refreshed OAuth2 token",
logger.WarnCtx(
ctx,
"cannot persist refreshed OAuth2 token",
log.String("connector_id", connector.ID.String()),
log.Error(err),
)
}
}
logger.InfoCtx(ctx, "sync completed successfully",
logger.InfoCtx(
ctx,
"sync completed successfully",
log.Duration("sync_duration", duration),
log.Int("users_created", stats.Created),
log.Int("users_updated", stats.Updated),
@@ -141,7 +147,9 @@ func (r *BridgeRunner) transitionToFailed(
bridge.State = coredata.SCIMBridgeStateDisabled
bridge.NextSyncAt = nil
logger.ErrorCtx(ctx, "bridge disabled due to max consecutive failures",
logger.ErrorCtx(
ctx,
"bridge disabled due to max consecutive failures",
log.Duration("sync_duration", duration),
log.Int("consecutive_failures", bridge.ConsecutiveFailures),
log.Int("max_consecutive_failures", r.cfg.MaxConsecutiveFailures),
@@ -153,7 +161,9 @@ func (r *BridgeRunner) transitionToFailed(
nextSync := now.Add(backoff)
bridge.NextSyncAt = &nextSync
logger.ErrorCtx(ctx, "sync failed, will retry with backoff",
logger.ErrorCtx(
ctx,
"sync failed, will retry with backoff",
log.Duration("sync_duration", duration),
log.Int("consecutive_failures", bridge.ConsecutiveFailures),
log.Duration("next_retry_in", backoff),
@@ -162,7 +172,9 @@ func (r *BridgeRunner) transitionToFailed(
}
if err := bridge.Update(ctx, conn, scope); err != nil {
logger.ErrorCtx(ctx, "cannot update bridge after failed sync",
logger.ErrorCtx(
ctx,
"cannot update bridge after failed sync",
log.String("new_state", string(bridge.State)),
log.Error(err),
)

View File

@@ -156,7 +156,9 @@ func (r *BridgeRunner) createGoogleWorkspaceProvider(
providerName := dbConnector.Provider.String()
refreshCfg := r.connectorRegistry.GetOAuth2RefreshConfig(providerName)
if refreshCfg == nil {
logger.WarnCtx(ctx, "no OAuth2 refresh config found, using static token",
logger.WarnCtx(
ctx,
"no OAuth2 refresh config found, using static token",
log.String("connector_id", dbConnector.ID.String()),
log.String("connector_provider", providerName),
)

View File

@@ -132,17 +132,21 @@ func NewService(
}
svc.SAMLService = samlService
svc.SCIMService = scim.NewService(svc.pg, cfg.Logger.Named("scim"), scim.ServiceConfig{
TracerProvider: cfg.TracerProvider,
Registerer: cfg.Registerer,
EncryptionKey: cfg.EncryptionKey,
ConnectorRegistry: cfg.ConnectorRegistry,
BridgeRunner: scim.BridgeRunnerConfig{
Interval: cfg.SCIMBridgeSyncInterval,
PollInterval: cfg.SCIMBridgePollInterval,
BaseURL: cfg.BaseURL,
svc.SCIMService = scim.NewService(
svc.pg,
cfg.Logger.Named("scim"),
scim.ServiceConfig{
TracerProvider: cfg.TracerProvider,
Registerer: cfg.Registerer,
EncryptionKey: cfg.EncryptionKey,
ConnectorRegistry: cfg.ConnectorRegistry,
BridgeRunner: scim.BridgeRunnerConfig{
Interval: cfg.SCIMBridgeSyncInterval,
PollInterval: cfg.SCIMBridgePollInterval,
BaseURL: cfg.BaseURL,
},
},
})
)
svc.samlDomainVerifier = NewSAMLDomainVerifier(
pgClient,

View File

@@ -115,7 +115,9 @@ func (c *Client) ChatCompletion(ctx context.Context, req *ChatCompletionRequest)
func (c *Client) ChatCompletionStream(ctx context.Context, req *ChatCompletionRequest) (ChatCompletionStream, error) {
ctx, span := startChatSpan(ctx, c.tracer, c.system, req)
c.logger.InfoCtx(ctx, "chat completion stream request",
c.logger.InfoCtx(
ctx,
"chat completion stream request",
log.String("model", req.Model),
log.Int("message_count", len(req.Messages)),
log.Int("tool_count", len(req.Tools)),

View File

@@ -73,7 +73,9 @@ func newTestClient(provider llm.Provider) (*llm.Client, *tracetest.SpanRecorder)
recorder := tracetest.NewSpanRecorder()
tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(recorder))
client := llm.NewClient(provider, "test",
client := llm.NewClient(
provider,
"test",
llm.WithTracerProvider(tp),
)
return client, recorder

View File

@@ -46,7 +46,9 @@ func startChatSpan(ctx context.Context, tracer trace.Tracer, system string, req
attrs = append(attrs, semconv.GenAIRequestStopSequences(req.StopSequences...))
}
return tracer.Start(ctx, spanName,
return tracer.Start(
ctx,
spanName,
trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attrs...),
)

View File

@@ -293,7 +293,9 @@ func (w *SendingWorker) failEmail(
email *coredata.Email,
processingError error,
) error {
w.logger.ErrorCtx(ctx, "sending worker failure",
w.logger.ErrorCtx(
ctx,
"sending worker failure",
log.Error(processingError),
log.String("email_id", email.ID.String()),
)

View File

@@ -148,13 +148,17 @@ func (w *MailingListWorker) processNext(ctx context.Context, sem chan struct{},
defer func() { <-sem }()
if err := w.sendAndCommit(nonCancelableCtx, &mlu); err != nil {
w.logger.ErrorCtx(nonCancelableCtx, "cannot send mailing list update",
w.logger.ErrorCtx(
nonCancelableCtx,
"cannot send mailing list update",
log.Error(err),
log.String("mailing_list_update_id", mlu.ID.String()),
)
if err := w.resetEnqueued(nonCancelableCtx, &mlu); err != nil {
w.logger.ErrorCtx(nonCancelableCtx, "cannot reset mailing list update to enqueued",
w.logger.ErrorCtx(
nonCancelableCtx,
"cannot reset mailing list update to enqueued",
log.Error(err),
log.String("mailing_list_update_id", mlu.ID.String()),
)

View File

@@ -149,8 +149,11 @@ var (
)
func (e ErrSignatureNotCancellable) Error() string {
return fmt.Sprintf("cannot cancel signature request: signature is in state %v, expected %v",
e.currentState, e.expectedState)
return fmt.Sprintf(
"cannot cancel signature request: signature is in state %v, expected %v",
e.currentState,
e.expectedState,
)
}
func (e ErrDocumentVersionNoChanges) Error() string {

View File

@@ -261,10 +261,15 @@ func (s OrganizationService) Update(
UpdatedAt: now,
}
fileSize, err = s.svc.fileManager.PutFile(ctx, fileRecord, req.File.Content, map[string]string{
"type": "organization-logo",
"organization-id": organization.ID.String(),
})
fileSize, err = s.svc.fileManager.PutFile(
ctx,
fileRecord,
req.File.Content,
map[string]string{
"type": "organization-logo",
"organization-id": organization.ID.String(),
},
)
if err != nil {
return fmt.Errorf("cannot upload logo file: %w", err)
}
@@ -316,10 +321,15 @@ func (s OrganizationService) Update(
UpdatedAt: now,
}
fileSize, err = s.svc.fileManager.PutFile(ctx, fileRecord, req.HorizontalLogoFile.Content, map[string]string{
"type": "organization-horizontal-logo",
"organization-id": organization.ID.String(),
})
fileSize, err = s.svc.fileManager.PutFile(
ctx,
fileRecord,
req.HorizontalLogoFile.Content,
map[string]string{
"type": "organization-horizontal-logo",
"organization-id": organization.ID.String(),
},
)
if err != nil {
return fmt.Errorf("cannot upload horizontal logo file: %w", err)
}

View File

@@ -347,7 +347,8 @@ func (s *Service) lockExportJob(ctx context.Context) (*coredata.ExportJob, error
exportJob := &coredata.ExportJob{}
var scope coredata.Scoper
err := s.pg.WithTx(ctx,
err := s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
if err := exportJob.LoadNextPendingForUpdateSkipLocked(ctx, tx); err != nil {
return fmt.Errorf("cannot load next pending export job: %w", err)

View File

@@ -39,10 +39,13 @@ func buildLLMClient(cfg LLMConfig, l *log.Logger, tp trace.TracerProvider, r pro
switch provider {
case "openai":
p := llmopenai.NewProvider(cfg.APIKey,
p := llmopenai.NewProvider(
cfg.APIKey,
llmopenai.WithHTTPClient(httpClient),
)
return llm.NewClient(p, "openai",
return llm.NewClient(
p,
"openai",
llm.WithLogger(l),
llm.WithTracerProvider(tp),
), nil

View File

@@ -764,7 +764,9 @@ func newTrustCenterHTTPRedirectHandler(proboService *probo.Service, l *log.Logge
// This is a trust center domain, redirect to HTTPS
httpsURL := "https://" + r.Host + r.URL.RequestURI()
l.InfoCtx(ctx, "HTTP request to trust center custom domain, redirecting to HTTPS",
l.InfoCtx(
ctx,
"HTTP request to trust center custom domain, redirecting to HTTPS",
log.String("domain", domain),
log.String("path", r.URL.Path),
log.String("to", httpsURL),

View File

@@ -26,13 +26,17 @@ import (
func LoggingMiddleware(logger *log.Logger) func(mcp.MethodHandler) mcp.MethodHandler {
return func(next mcp.MethodHandler) mcp.MethodHandler {
return func(ctx context.Context, method string, req mcp.Request) (mcp.Result, error) {
logger.InfoCtx(ctx, fmt.Sprintf("mcp %q method started", method),
logger.InfoCtx(
ctx,
fmt.Sprintf("mcp %q method started", method),
log.String("method", method),
log.Bool("has_params", req.GetParams() != nil),
)
if ctr, ok := req.(*mcp.CallToolRequest); ok {
logger.InfoCtx(ctx, fmt.Sprintf("calling %q tool", ctr.Params.Name),
logger.InfoCtx(
ctx,
fmt.Sprintf("calling %q tool", ctr.Params.Name),
log.String("tool_name", ctr.Params.Name),
)
}
@@ -42,21 +46,27 @@ func LoggingMiddleware(logger *log.Logger) func(mcp.MethodHandler) mcp.MethodHan
duration := time.Since(start)
if err != nil {
logger.ErrorCtx(ctx, fmt.Sprintf("mcp %q method failed", method),
logger.ErrorCtx(
ctx,
fmt.Sprintf("mcp %q method failed", method),
log.String("method", method),
log.Int64("duration_ms", duration.Milliseconds()),
log.Error(err),
)
} else {
logger.InfoCtx(ctx, fmt.Sprintf("mcp %q method completed", method),
logger.InfoCtx(
ctx,
fmt.Sprintf("mcp %q method completed", method),
log.String("method", method),
log.Int64("duration_ms", duration.Milliseconds()),
log.Bool("has_result", result != nil),
)
if ctr, ok := result.(*mcp.CallToolResult); ok {
logger.InfoCtx(ctx, "tool call result",
logger.InfoCtx(
ctx,
"tool call result",
log.Bool("is_error", ctr.IsError),
)
}

View File

@@ -57,7 +57,9 @@ func convertPanicToError(ctx context.Context, logger *log.Logger, panicValue any
}
// Log unexpected panics with stack trace
logger.ErrorCtx(ctx, "unexpected panic in MCP method handler",
logger.ErrorCtx(
ctx,
"unexpected panic in MCP method handler",
log.Any("panic", panicValue),
log.String("stack", string(debug.Stack())),
)

View File

@@ -21,10 +21,15 @@ import (
)
func allApproversCursor() *page.Cursor[coredata.MembershipProfileOrderField] {
return page.NewCursor(100, nil, page.Head, page.OrderBy[coredata.MembershipProfileOrderField]{
Field: coredata.MembershipProfileOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
})
return page.NewCursor(
100,
nil,
page.Head,
page.OrderBy[coredata.MembershipProfileOrderField]{
Field: coredata.MembershipProfileOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
},
)
}
func profileIDs(p *page.Page[*coredata.MembershipProfile, coredata.MembershipProfileOrderField]) []gid.GID {

View File

@@ -35,7 +35,9 @@ func RequireAPIKeyHandler(
correlationID = r.Header.Get("X-Correlation-ID")
}
logger.InfoCtx(ctx, "MCP authentication attempt",
logger.InfoCtx(
ctx,
"MCP authentication attempt",
log.String("correlation_id", correlationID),
log.String("path", r.URL.Path),
)
@@ -48,7 +50,9 @@ func RequireAPIKeyHandler(
return
}
logger.InfoCtx(ctx, "MCP authentication successful",
logger.InfoCtx(
ctx,
"MCP authentication successful",
log.String("correlation_id", correlationID),
log.String("identity_id", identity.ID.String()),
log.String("api_key_id", apiKey.ID.String()),

View File

@@ -283,9 +283,13 @@ func (r *mutationResolver) UpdateFullName(ctx context.Context, input types.Updat
return nil, gqlutils.Unauthenticatedf(ctx, "authentication is required to request access")
}
identity, err := r.iam.AccountService.UpdateIdentity(ctx, identity.ID, &iam.UpdateIdentityRequest{
FullName: input.FullName,
})
identity, err := r.iam.AccountService.UpdateIdentity(
ctx,
identity.ID,
&iam.UpdateIdentityRequest{
FullName: input.FullName,
},
)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot update identity", log.Error(err))
return nil, gqlutils.Internal(ctx)

View File

@@ -114,7 +114,8 @@ func (t TracingExtension) InterceptOperation(ctx context.Context, next graphql.O
}
if resp.Errors != nil {
t.logger.ErrorCtx(ctx,
t.logger.ErrorCtx(
ctx,
fmt.Sprintf("%s %s failed %s", operationType, operationName, duration.String()),
log.String("graphql_operation_name", operationName),
log.String("graphql_operation_type", operationType),
@@ -122,7 +123,8 @@ func (t TracingExtension) InterceptOperation(ctx context.Context, next graphql.O
log.Any("graphql_operation_errors", resp.Errors),
)
} else {
t.logger.InfoCtx(ctx,
t.logger.InfoCtx(
ctx,
fmt.Sprintf("%s %s succeed %s", operationType, operationName, duration.String()),
log.String("graphql_operation_name", operationName),
log.String("graphql_operation_type", operationType),

View File

@@ -17,12 +17,12 @@ package trust
import "errors"
var (
ErrCustomDomainNotFound = errors.New("custom domain not found")
ErrPageNotFound = errors.New("page not found")
ErrMembershipNotFound = errors.New("membership not found")
ErrUserNotFound = errors.New("user not found")
ErrUserInactive = errors.New("user inactive")
ErrDocumentAccessNotFound = errors.New("document access not found")
ErrCustomDomainNotFound = errors.New("custom domain not found")
ErrPageNotFound = errors.New("page not found")
ErrMembershipNotFound = errors.New("membership not found")
ErrUserNotFound = errors.New("user not found")
ErrUserInactive = errors.New("user inactive")
ErrDocumentAccessNotFound = errors.New("document access not found")
ErrNDAFileNotFound = errors.New("NDA file not found")
ErrDocumentNotFound = errors.New("document not found")
ErrDocumentNotVisible = errors.New("document not visible")