{"record":{"id":"10ea564d2b15a213","repo":"larksuite/cli","slug":"l3-inputschema-yes-property-v-inconsistent-wit","errorCode":null,"errorMessage":"L3: inputSchema `yes` property=%v inconsistent with risk=%q","messagePattern":"L3: inputSchema `yes` property=(.+?) inconsistent with risk=%q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/schema/lint.go","lineNumber":97,"sourceCode":"\t\t\t}\n\t\t}\n\t}\n\n\t// ---- L3: cross-field self-consistency ----\n\tdangerExpected := env.Meta.Risk == core.RiskWrite || env.Meta.Risk == core.RiskHighRiskWrite\n\tif env.Meta.Danger != dangerExpected {\n\t\terrs = append(errs, fmt.Errorf(\"L3: _meta.danger=%v inconsistent with risk=%q\", env.Meta.Danger, env.Meta.Risk))\n\t}\n\n\t// `yes` lives at inputSchema.properties.yes (sibling of params/data),\n\t// injected only for risk == RiskHighRiskWrite.\n\thasYes := false\n\tif env.InputSchema != nil && env.InputSchema.Properties != nil {\n\t\t_, hasYes = env.InputSchema.Properties.Map[\"yes\"]\n\t}\n\twantYes := env.Meta.Risk == core.RiskHighRiskWrite\n\tif hasYes != wantYes {\n\t\terrs = append(errs, fmt.Errorf(\"L3: inputSchema `yes` property=%v inconsistent with risk=%q\", hasYes, env.Meta.Risk))\n\t}\n\n\tif len(env.Meta.AccessTokens) == 0 {\n\t\terrs = append(errs, errors.New(\"L3: _meta.access_tokens must not be empty\"))\n\t}\n\tfor _, t := range env.Meta.AccessTokens {\n\t\tif !validAccessTokens[t] {\n\t\t\terrs = append(errs, fmt.Errorf(\"L3: _meta.access_tokens contains invalid value %q (allowed: user, bot)\", t))\n\t\t}\n\t}\n\n\treturn errs\n}\n\n// walkForL2 recursively applies per-field L2 checks (format:binary on\n// non-string; minimum>=maximum) plus the sub-object required-exists invariant.\n// Required only matters on object-typed Properties (e.g. the params / data\n// wrappers); leaf scalars ignore it.","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/schema/lint.go#L79-L115","documentation":"Envelope-level (L3) lint rule in internal/schema/lint.go's lintEnvelope. The inputSchema must contain a boolean `yes` property if and only if the envelope is a high-risk write (Meta.Risk == core.RiskHighRiskWrite). It enforces that dangerous operations expose an explicit confirmation field, and it fires when that correspondence is broken in either direction.","triggerScenarios":"Registering an envelope whose Meta.Risk is RiskHighRiskWrite but whose InputSchema.Properties has no `yes` key, or declaring a `yes` property on an envelope whose risk is not high-risk-write.","commonSituations":"Promoting a shortcut to high-risk and forgetting to add the `yes` confirmation field; copying a high-risk envelope as a template for a low-risk command and leaving `yes` behind; editing the risk constant in meta without re-linting.","solutions":["Add a boolean `yes` property to InputSchema.Properties for high-risk writes","Remove the `yes` property if the operation is not a high-risk write","Set Meta.Risk to RiskHighRiskWrite if the operation really needs confirmation","Run the lint (TestAllEnvelopesPass) to see the reported property/risk mismatch"],"exampleFix":"// before\nMeta: {Risk: core.RiskHighRiskWrite}, InputSchema: {Properties: {Map: {\"task_id\": ...}}}\n// after\nInputSchema: {Properties: {Map: {\"task_id\": ..., \"yes\": {Type: \"boolean\", Description: \"confirm high-risk write\"}}}}","handlingStrategy":"validation","validationCode":"for _, env := range envelopes {\n  _, hasYes := env.InputSchema.Properties.Map[\"yes\"]\n  if hasYes != (env.Meta.Risk == core.RiskHighRiskWrite) {\n    t.Errorf(\"envelope %s: `yes` property / risk mismatch\", env.Name)\n  }\n}","typeGuard":"func needsYesConfirmation(risk core.Risk) bool { return risk == core.RiskHighRiskWrite }","tryCatchPattern":null,"preventionTips":["Always add a boolean `yes` property when declaring RiskHighRiskWrite","Run go test ./internal/schema (TestAllEnvelopesPass) before committing envelope changes","Copy envelope templates only from same-risk commands","Derive risk and confirmation field together in generator code"],"tags":["schema","lint","risk"],"backgroundTag":"schema-validation-failed","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}