Skip to content

fix(slides): local XML precheck, 99991400 backoff, quota code registration#1383

Open
ViperCai wants to merge 1 commit into
mainfrom
fix/slides-xml-wellformed-precheck
Open

fix(slides): local XML precheck, 99991400 backoff, quota code registration#1383
ViperCai wants to merge 1 commit into
mainfrom
fix/slides-xml-wellformed-precheck

Conversation

@ViperCai

@ViperCai ViperCai commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Background

Based on the 2026-06-08 slides write-path error telemetry analysis (see internal analysis doc), failures on the CLI/OpenAPI path concentrate in four buckets: XML well-formedness errors (bare &, unclosed tags, <?xml ?> declarations rejected by nodeserver), 99991400 rate limits aborting batch submissions, commercial quota codes 9000308x falling through to the unknown classification with no actionable hint, and skill guidance lacking a tag-whitelist ban. This PR lands all four agreed fixes.

Changes

1. Local XML well-formedness precheck (shortcuts/slides/)

  • New checkXMLWellFormed: pure syntax validation using Go's stdlib encoding/xml (same parser family as the backend, false-positive risk ≈ 0); explicitly rejects <?xml ?> declarations (the backend's error for these is unreadable: "?xml not provide the implement"); deliberately allows multiple top-level elements (legal in block_insert fragments)
  • Wired into +create --slides (at Validate, so a bad slide no longer leaves a half-built deck behind) and +replace-slide --parts replacement/insertion
  • Errors carry the line number plus escaping guidance; rejected locally with exit=2, zero API calls

2. 99991400 rate-limit backoff (retryOnRateLimit)

  • 99991400 has long been registered Retryable:true in codemeta, but no slides loop actually retried — a single per-second frequency-window hit aborted the whole batch
  • New backoff helper (up to 2 retries, 1s/2s exponential backoff, announced on stderr, context-cancellable), matching on the typed rate-limit subtype + retryable flag; pattern mirrors the existing wiki +node-create lock-contention retry
  • Wired into the +create consecutive slide POST loop and uploadSlidesMedia (covers +media-upload and the placeholder image upload loop)
  • Upload switched from the deprecated UploadDriveMediaAll to UploadDriveMediaAllTyped (the retry match requires typed errors, and this aligns with the slides typed-error migration in feat(slides): emit typed error envelopes across the slides domain #1349)

3. Register commercial quota codes 90003086/87/88 (internal/errclass + internal/output)

  • Cloud-space explorer billing codes, passed through verbatim by slides_ai create / drive import_tasks as HTTP 200 with body code≠0; previously fell to SubtypeUnknown
  • Classified as CategoryAPI + quota_exceeded, not retryable (plan limits — retrying can never succeed), with per-code hints (86/87 → upgrade the plan or delete documents to free quota; 88 → ask the tenant admin to enable the docs module)

4. lark-slides skill tag-whitelist ban (skills/lark-slides/)

  • xml-schema-quick-ref.md (already mandatory reading before generating any XML per SKILL.md): never write tags outside the whitelist + name the six tags with confirmed online rejections (audio/video/timeline/animation/trigger/header) + substitution table + escaping rules
  • Fixed a doc self-contradiction: examples in quick-ref and xml-format-guide carried <?xml ?> declarations, contradicting backend behavior (and this PR's precheck); all removed

Compatibility notes

  • Malformed XML is now rejected locally instead of by the backend: error type changes from api to validation (different exit code); +create no longer leaves a partial presentation behind
  • +media-upload failure envelopes switch from legacy to typed, aligning with the rest of the slides domain; success paths unchanged
  • A genuinely rate-limited call now waits up to 3 extra seconds in exchange for the batch surviving

Testing

  • Unit + httpmock integration tests: 17-case precheck table, 5 backoff sub-cases, one "first response 400/99991400 → retry → batch completes" integration test each for create/upload; LookupCodeMeta pins for the quota codes
  • Live verification against the real feishu.cn API:
    • All 5 precheck negative cases rejected locally (exit=2, zero requests); positive cases with &amp;/&lt; entities created and replaced successfully, read back to confirm persistence — no false positives
    • 18 concurrent +media-upload calls hit 3 real 99991400 responses; all retried after the 1s backoff and succeeded, 18/18 zero failures (before this change those 3 would have errored out)
    • 90003086/87/88 cannot be triggered live (requires exhausting a plan's quota); acceptance via post-release telemetry

Summary by CodeRabbit

  • New Features

    • Pre-flight XML validation for slide fragments; per-fragment error reporting.
    • Exponential-backoff retries for slide creation and media uploads on rate-limit responses.
    • Image-placeholder handling decodes XML-escaped local paths before lookup.
  • Bug Fixes

    • Added per-code, non-retryable user hints for docs/slides quota and module-unbundled errors.
    • Improved hint precedence so per-code hints win when available.
  • Documentation

    • Strengthened XML guidance: omit in fragments, use XML entity escaping, follow element whitelist.
  • Tests

    • Expanded tests for XML validation, placeholder decoding, retry/backoff behavior, and hint precedence.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Registers three new docs/drive quota error codes with per-code Hints and adjusts hint precedence; adds XML fragment well-formedness checks, XML-entity-aware placeholder handling, and exponential-backoff rate-limit retry helpers integrated into Slides create/upload/replace flows; adds tests and updates docs.

Changes

Quota Error Code Registration

Layer / File(s) Summary
CodeMeta shape and per-code Hint
internal/errclass/codemeta.go
Adds optional CodeMeta.Hint field and documents its dispatcher-only usage for CategoryAPI hint selection.
Drive error code mappings
internal/errclass/codemeta_drive.go, internal/errclass/codemeta_drive_test.go
Adds mappings for codes 90003086, 90003087, 90003088 with Subtype and per-code Hint strings; tests assert CategoryAPI/Subtype and Retryable=false.
Lark API error constants and legacy hints
internal/output/lark_errors.go
Adds exported constants LarkErrDocsCreatePremiumQuota, LarkErrDocsCreateA2Quota, LarkErrDocsModuleUnbundled and extends legacyHints with user-facing guidance strings.
Hint precedence in BuildAPIError
internal/errclass/classify.go, internal/errclass/classify_test.go
Apply per-code CodeMeta.Hint when base.Hint is empty before falling back to subtype APIHint; add tests validating per-code hint selection and server-detail precedence.

Slides Reliability: XML Validation and Rate-Limit Retry

Layer / File(s) Summary
Rate-limit retry infrastructure
shortcuts/slides/helpers.go, shortcuts/slides/helpers_test.go
Adds isRateLimitedErr, retryOnRateLimit, and retry configuration (max retries, base delay); tests cover retry behavior, exhaustion, non-rate-limit errors, and cancellation.
Image placeholder XML entity handling
shortcuts/slides/helpers.go, shortcuts/slides/helpers_test.go
Decode XML entities in @<path> captures via placeholderFilePath, deduplicate decoded paths, and use decoded keys for replacement; regression tests added.
XML well-formedness validation helper
shortcuts/slides/helpers.go, shortcuts/slides/helpers_test.go
Introduces checkXMLWellFormed which tokenizes fragments, rejects <?xml ...?> PIs, reports line-numbered syntax errors, and adds table-driven tests.
SlidesCreate validation and retry integration
shortcuts/slides/slides_create.go, shortcuts/slides/slides_create_test.go
Prechecks --slides fragments with checkXMLWellFormed and wraps per-slide add POSTs with retryOnRateLimit; tests added for precheck rejection and retry-on-rate-limit success/exhaustion.
SlidesMediaUpload rate-limit retry integration
shortcuts/slides/slides_media_upload.go, shortcuts/slides/slides_media_upload_test.go
Wraps upload_all uploads in retryOnRateLimit via UploadDriveMediaAllTyped to preserve file_token across retries; test asserts retry then success.
SlidesReplaceSlide XML validation integration
shortcuts/slides/slides_replace_slide.go, shortcuts/slides/slides_replace_slide_test.go
Runs checkXMLWellFormed on replacement/insertion fragments in validateReplaceParts, converts failures into indexed --parts invalid-argument errors; tests cover malformed fragments.
XML submission constraints documentation
skills/lark-slides/references/xml-format-guide.md, skills/lark-slides/references/xml-schema-quick-ref.md
Docs updated to forbid XML processing instructions in fragments, require root-starting fragments, add whitelist/escaping guidance, and remove <?xml ...?> from examples.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI (shortcut)
  participant Retry as retryOnRateLimit
  participant SlidesAPI as Slides API
  CLI->>Retry: call operation (add slide / upload / replace part)
  Retry->>SlidesAPI: POST request
  SlidesAPI-->>Retry: response (success or rate-limit error)
  alt rate-limit error (retryable)
    Retry->>Retry: wait (exponential backoff) and log retry
    Retry->>SlidesAPI: retry POST
  else success or non-retryable error
    Retry-->>CLI: return result or error
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • larksuite/cli#389: Prior work on slides +create flow that this PR augments with prevalidation and retry handling.
  • larksuite/cli#1232: Overlaps on CodeMeta/hint handling and BuildAPIError hint precedence changes.
  • larksuite/cli#1250: Related work on quota/exceeded APIHint handling and classifier behavior.

Suggested labels

domain/ccm, feature

Suggested reviewers

  • fangshuyu-768

Poem

🐇 I nibble bugs and stitch a patch,
Three quota codes join the batch.
XML tidy — no stray PI,
Retries wait while rate limits sigh.
Slides snap in place; onward we dispatch.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the three main changes: local XML precheck, 99991400 rate-limit backoff, and quota code registration.
Description check ✅ Passed The PR description provides comprehensive coverage of all required template sections: clear background and motivation, detailed changes across four areas, thorough testing description, and explicit compatibility notes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/slides-xml-wellformed-precheck

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size/M Single-domain feat or fix with limited business impact label Jun 10, 2026
@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.64865% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 72.77%. Comparing base (154ecdb) to head (6c79ad9).

Files with missing lines Patch % Lines
shortcuts/slides/helpers.go 97.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1383      +/-   ##
==========================================
+ Coverage   72.75%   72.77%   +0.02%     
==========================================
  Files         730      730              
  Lines       69030    69088      +58     
==========================================
+ Hits        50224    50281      +57     
- Misses      15034    15035       +1     
  Partials     3772     3772              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@6c79ad95b3693d25f3979db53cc928cb3b98c6d7

🧩 Skill update

npx skills add larksuite/cli#fix/slides-xml-wellformed-precheck -y -g

@ViperCai ViperCai force-pushed the fix/slides-xml-wellformed-precheck branch from 535659c to 27a2836 Compare June 10, 2026 08:57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/errclass/codemeta_drive.go`:
- Around line 16-24: The comment and mapping for error code 90003088 are
misleading: update the comment text near the commercial plan quota block to
state that “free quota” applies only to codes 90003086 and 90003087, and change
the mapping for 90003088 in internal/errclass/codemeta_drive.go from
errs.SubtypeQuotaExceeded to a more appropriate subtype such as
errs.SubtypeFailedPrecondition (or ensure a code-specific hint override is
provided) so that the default quota-exceeded hint is not applied to the “tenant
has not purchased / been granted the docs module” case; adjust the inline
comment for 90003088 accordingly to reflect the non-quota precondition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e4011aa7-9bd1-4f40-ad1f-0214fee63cdd

📥 Commits

Reviewing files that changed from the base of the PR and between e794fd5 and 535659c.

📒 Files selected for processing (13)
  • internal/errclass/codemeta_drive.go
  • internal/errclass/codemeta_drive_test.go
  • internal/output/lark_errors.go
  • shortcuts/slides/helpers.go
  • shortcuts/slides/helpers_test.go
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_create_test.go
  • shortcuts/slides/slides_media_upload.go
  • shortcuts/slides/slides_media_upload_test.go
  • shortcuts/slides/slides_replace_slide.go
  • shortcuts/slides/slides_replace_slide_test.go
  • skills/lark-slides/references/xml-format-guide.md
  • skills/lark-slides/references/xml-schema-quick-ref.md

Comment thread internal/errclass/codemeta_drive.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
shortcuts/slides/helpers.go (1)

361-367: ⚡ Quick win

Preserve parser causes when wrapping XML parse failures.

Line [363] and Line [367] drop the original parse error. Add .WithCause(err) (or .WithCause(syn)) so unwrap and root-cause tracing remain intact.

Proposed fix
 		if err != nil {
 			if syn, ok := err.(*xml.SyntaxError); ok {
 				return errs.NewValidationError(errs.SubtypeInvalidArgument,
 					"XML not well-formed at line %d: %s (escape literal & as &amp; and < as &lt; in text)",
-					syn.Line, syn.Msg)
+					syn.Line, syn.Msg).WithCause(syn)
 			}
-			return errs.NewValidationError(errs.SubtypeInvalidArgument, "XML not well-formed: %v", err)
+			return errs.NewValidationError(errs.SubtypeInvalidArgument, "XML not well-formed: %v", err).WithCause(err)
 		}

As per coding guidelines: "Preserve underlying errors with .WithCause(err) so errors.Is and errors.Unwrap continue working."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shortcuts/slides/helpers.go` around lines 361 - 367, The validation error
returned when XML parsing fails (the branch that checks for xml.SyntaxError and
the generic err branch calling errs.NewValidationError) currently drops the
original parse error; update both return statements to attach the original cause
by calling .WithCause(syn) for the xml.SyntaxError branch and .WithCause(err)
for the generic branch so unwrap/root-cause tracing (errors.Is/Unwrap) works
properly; look for the block that inspects err, the type assertion to
xml.SyntaxError, and the calls to errs.NewValidationError and append the
corresponding .WithCause(...) before returning.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/slides/helpers.go`:
- Around line 49-57: The loop currently calls fn() even when ctx is already
cancelled and returns bare ctx.Err(); update the retry loop in
shortcuts/slides/helpers.go (the block using variables
slidesRateLimitMaxRetries, slidesRateLimitBaseDelay, errOut and calling fn()) to
check ctx.Done() before dispatching fn() on every attempt and return a typed
cancellation error instead of ctx.Err() (use
errs.NewValidationError(errs.SubtypeFailedPrecondition, "...").WithHint(...) or
the appropriate errs.* typed error per guideline). Also replace any bare
ctx.Err() returns inside the select or after cancellation checks with the chosen
typed errs.* error so callers get command-facing typed failures.

---

Nitpick comments:
In `@shortcuts/slides/helpers.go`:
- Around line 361-367: The validation error returned when XML parsing fails (the
branch that checks for xml.SyntaxError and the generic err branch calling
errs.NewValidationError) currently drops the original parse error; update both
return statements to attach the original cause by calling .WithCause(syn) for
the xml.SyntaxError branch and .WithCause(err) for the generic branch so
unwrap/root-cause tracing (errors.Is/Unwrap) works properly; look for the block
that inspects err, the type assertion to xml.SyntaxError, and the calls to
errs.NewValidationError and append the corresponding .WithCause(...) before
returning.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7368ce9f-cee1-4e7f-9caa-050f08a0c66b

📥 Commits

Reviewing files that changed from the base of the PR and between 535659c and 27a2836.

📒 Files selected for processing (13)
  • internal/errclass/codemeta_drive.go
  • internal/errclass/codemeta_drive_test.go
  • internal/output/lark_errors.go
  • shortcuts/slides/helpers.go
  • shortcuts/slides/helpers_test.go
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_create_test.go
  • shortcuts/slides/slides_media_upload.go
  • shortcuts/slides/slides_media_upload_test.go
  • shortcuts/slides/slides_replace_slide.go
  • shortcuts/slides/slides_replace_slide_test.go
  • skills/lark-slides/references/xml-format-guide.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
✅ Files skipped from review due to trivial changes (4)
  • internal/errclass/codemeta_drive.go
  • internal/output/lark_errors.go
  • skills/lark-slides/references/xml-format-guide.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_replace_slide.go
  • shortcuts/slides/slides_replace_slide_test.go
  • shortcuts/slides/slides_media_upload.go
  • shortcuts/slides/slides_media_upload_test.go
  • shortcuts/slides/slides_create_test.go
  • internal/errclass/codemeta_drive_test.go
  • shortcuts/slides/helpers_test.go

Comment thread shortcuts/slides/helpers.go
@ViperCai ViperCai force-pushed the fix/slides-xml-wellformed-precheck branch 2 times, most recently from 0697b81 to c76a6fa Compare June 10, 2026 09:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/slides/helpers_test.go`:
- Around line 440-492: The tests in TestCheckXMLWellFormed only check error
message substrings; update them to assert the typed validation error and subtype
from checkXMLWellFormed: use errors.As (or errs.ProblemOf) to confirm the
returned error is a *errs.ValidationError and that its Subtype equals
errs.SubtypeInvalidArgument where applicable, then keep the existing substring
checks for line numbers/messages; locate this logic inside the
TestCheckXMLWellFormed table-driven loop and update the error-path branch that
currently inspects err.Error() to perform the typed assertions against
*errs.ValidationError and its Subtype before verifying the message content.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83854856-c528-4971-9e94-9bc8672fa4d4

📥 Commits

Reviewing files that changed from the base of the PR and between 0697b81 and c76a6fa.

📒 Files selected for processing (16)
  • internal/errclass/classify.go
  • internal/errclass/classify_test.go
  • internal/errclass/codemeta.go
  • internal/errclass/codemeta_drive.go
  • internal/errclass/codemeta_drive_test.go
  • internal/output/lark_errors.go
  • shortcuts/slides/helpers.go
  • shortcuts/slides/helpers_test.go
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_create_test.go
  • shortcuts/slides/slides_media_upload.go
  • shortcuts/slides/slides_media_upload_test.go
  • shortcuts/slides/slides_replace_slide.go
  • shortcuts/slides/slides_replace_slide_test.go
  • skills/lark-slides/references/xml-format-guide.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
✅ Files skipped from review due to trivial changes (1)
  • skills/lark-slides/references/xml-format-guide.md
🚧 Files skipped from review as they are similar to previous changes (11)
  • shortcuts/slides/slides_create.go
  • internal/errclass/codemeta_drive.go
  • internal/output/lark_errors.go
  • internal/errclass/codemeta_drive_test.go
  • shortcuts/slides/slides_media_upload.go
  • skills/lark-slides/references/xml-schema-quick-ref.md
  • shortcuts/slides/slides_replace_slide_test.go
  • shortcuts/slides/slides_create_test.go
  • shortcuts/slides/slides_media_upload_test.go
  • shortcuts/slides/helpers.go
  • shortcuts/slides/slides_replace_slide.go

Comment thread shortcuts/slides/helpers_test.go
@ViperCai ViperCai force-pushed the fix/slides-xml-wellformed-precheck branch 2 times, most recently from 38b1201 to ebec91e Compare June 11, 2026 03:43
…ation

Lands the four agreed fixes from the 2026-06-08 slides write-path
telemetry analysis:

1. Local XML well-formedness precheck (shortcuts/slides/)
   - checkXMLWellFormed: pure syntax validation via stdlib encoding/xml
     (same parser family as the backend, false-positive risk ~0);
     explicitly rejects <?xml ?> declarations; deliberately allows
     multiple top-level elements (legal in block_insert fragments)
   - wired into +create --slides (at Validate, so a bad slide no longer
     leaves a half-built deck) and +replace-slide --parts
     replacement/insertion; errors carry line numbers + escaping
     guidance, rejected locally with zero API calls

2. 99991400 rate-limit backoff (retryOnRateLimit)
   - the code was registered Retryable:true but no slides loop actually
     retried, so one frequency-window hit aborted the whole batch
   - up to 2 retries with 1s/2s backoff, announced on stderr,
     context-cancellable; wired into the +create slide POST loop and
     uploadSlidesMedia (+media-upload and the placeholder upload loop)
   - upload switched to UploadDriveMediaAllTyped (retry match requires
     typed errors; aligns with the slides typed migration)

3. Quota codes 90003086/87/88 registered (internal/errclass + output)
   - cloud-space explorer billing codes passed through as HTTP 200 with
     body code!=0; previously fell to SubtypeUnknown
   - now CategoryAPI + quota_exceeded, not retryable, with per-code
     hints (upgrade plan / free quota / ask admin to enable the module)

4. lark-slides skill tag-whitelist ban (skills/lark-slides/)
   - quick-ref: never write tags outside the whitelist, name the six
     confirmed-rejected tags (audio/video/timeline/animation/trigger/
     header), substitution table, escaping rules
   - removed <?xml ?> declarations from all examples (contradicted
     backend behavior and the new precheck)

Tested with unit + httpmock integration tests, plus live verification
against the real feishu.cn API: all precheck negatives rejected locally,
no false positives on real create/replace, and 18 concurrent uploads hit
3 real 99991400 responses which all retried and succeeded (18/18).
@ViperCai ViperCai force-pushed the fix/slides-xml-wellformed-precheck branch from ebec91e to 6c79ad9 Compare June 11, 2026 06:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant