You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Trace] Template de-dup: de-duplicate SDK doc boilerplate across docs/SDKs #173
Trace task: template-detector.mjs, config/anti-ai-rules.json, and the CONTENT SOP rule
for "Crawled - currently not indexed": de-duplicate before anything else.
Evidence: URL Inspection shows Google refusing to index substantial SDK pages: docs/SDKs/javascript (4,186 words, crawled - not indexed), python, quote-javascript, webhooks-java, deliverable-go, deliverable-php (crawled - not indexed), java
(discovered - not indexed). template-detector.mjs found the same 5-word phrases repeated
across 15 of the 27 live (non-Ruby) SDK pages (a first pass with the tool's own reporting
quirks read this as ~17; see "Template detector" below), concentrated in a generic "Error
Handling" intro sentence plus a 7-row status-code table with identical English wording
(Invalid or missing API key, Invalid request parameters, Too many requests, Network connectivity issues) copy-pasted regardless of language or product. queries.json shows
real developer demand: "python digital signature sdk" (433 impressions, currently ranking on
the dotcom guide /guides/sign-documents-with-python, not this docs page), "php digital
signature sdk" (378, same pattern), "javascript pdf signature integration" (337, same
pattern). Data source: queries.json was generated by queries.py, which calls the Google Search Console API directly
(searchAnalytics.query on sc-domain:turbodocx.com via a gcloud auth application-default print-access-token bearer token), not PostHog's GSC warehouse tables;
re-checked all three figures against the file directly before citing them here.
Root cause: two layers of duplication.
docs/SDKs/deliverable-{go,php,java,javascript,python}.md and docs/SDKs/partner-{go,php,java,javascript,python}.md (10 files) each carried a full copy
of the generic error-type table that belongs, once, on that language's canonical page
(javascript.md, python.md, go.md, php.md, java.md). quote-*.md and webhooks-*.md had no such generic error table to begin with; not part of this fix. (They
have their own, separate cross-language duplication in their product-intro paragraphs,
disclosed further down, unrelated to the error-table issue this fixes.)
The 5 canonical pages themselves opened ## Error Handling with the identical sentence
"The SDK provides typed error(s)/exception(s) for different ... scenarios", regardless of
language. Three of those five (javascript.md, python.md, java.md) are themselves
evidence pages Google won't index.
Fix, part 1 (10 deliverable/partner pages): replaced the generic intro + table with a
short paragraph naming an error each operation actually raises (verified against /home/nicolas/repos/SDK, e.g. Go's NotFoundError on an unknown TemplateID, PHP's AuthenticationException when the partner API key or partner ID is wrong), followed by a
link to the language's own Error Handling reference for the full table. Kept the genuinely useful,
already-differentiated code samples (Go's errors.As, PHP's typed exceptions, Java's nested TurboDocxException.* classes, the partner-specific IOException/409-conflict notes).
Fix, part 2 (5 canonical pages): rewrote each intro to state that language's real,
source-verified error-handling idiom instead of the shared sentence:
go.md: errors embed TurboDocxError by value; match with errors.As, read fields
directly (no getters). Added the ConflictError row/case that was missing from the table
(it exists in packages/go-sdk/http.go but wasn't documented).
php.md: statusCode/errorCode are public readonly properties; PHP's inherited Exception::getCode() is hardcoded to 0 by the constructor, so it never carries the
error code, a genuine footgun worth calling out. Added the AuthorizationException and ConflictException rows/catches that were missing (both exist in packages/php-sdk/src/Exceptions/) but weren't documented, even though partner-php.md
and deliverable-php.md already referenced them.
java.md: every exception is a nested static class of TurboDocxException
(TurboDocxException.ValidationException, not a top-level import); each of the 7 named
subclasses falls back to its own DEFAULT_CODE via a shared orDefault helper
(TurboDocxException.java) so getCode() is populated for those, though the bare TurboDocxException thrown for an unmapped status has no such fallback.
javascript.md: code is a plain string the HTTP client passes through from the API
response when present (e.g. QUOTE_NOT_FOUND) and only falls back to the class default
otherwise, per the docstring in packages/js-sdk/src/utils/errors.ts.
python.md: every subclass sets its own DEFAULT_CODE class attribute
(packages/py-sdk/src/turbodocx_sdk/http.py); catch the most specific exception first
since except TurboDocxError also matches its subclasses.
Bugs found while verifying code samples against SDK source, both in index.md:
The PHP error-handling example called $e->getCode(), but PHP's Exception::getCode() is
hardcoded to 0 by TurboDocxException's constructor (parent::__construct($message, 0, $previous) in packages/php-sdk/src/Exceptions/TurboDocxException.php); the real field is
the public readonly $e->errorCode. Fixed.
The Java example imported com.turbodocx.sdk.* (the SDK's real package is com.turbodocx,
no .sdk), returned a SigningResult type that doesn't exist in the SDK, and called turboSign.sendSignature(...) on a bare variable instead of the actual builder pattern, client.turboSign().sendSignature(...). All three didn't match java.md's own correct
examples elsewhere in this same repo. Fixed to match; also added the com.turbodocx.models.* import SendSignatureResponse needs.
The Go example matched errors.As(err, &turboErr) against *sdk.TurboDocxError only. Go's errors.As requires the target's concrete type to match the error's; *sdk.ValidationError
(and the 5 other named error types) is a distinct type from *sdk.TurboDocxError even
though it embeds it, and neither implements Unwrap/As, so this check silently failed to
match any of the 6 named error types and only caught the generic unmapped-status case; the VALIDATION_ERROR branch shown in the example was dead code. Fixed to match *sdk.ValidationError directly.
The Python example printed e.message. TurboDocxError.__init__ never sets self.message (nor does Python 3's Exception), so this raises AttributeError at
runtime. Fixed to {e} (str(e)), matching python.md's own examples.
The "code is always populated" line just above these tabs had the same gap the
language-page correction below describes. Qualified it the same way.
Correction found on a second pass (5 deliverable-*.md pages): my first commit claimed ValidationError fires when a variable is missing "placeholder or mimeType". Checked RapidDocxBackend/src/handlers/Deliverable/DeliverableGenerationHandlers.ts: the actual Variable interface used by the generate-deliverable request body has placeholder: string
(required, no ?) but mimeType?: string (optional, has ?), the opposite emphasis from
what I'd written. Couldn't find the runtime validation that actually rejects a missing placeholder (the handler doesn't appear to check it before using it), so rather than assert
an unverified 400, all 5 pages now say "missing a required field" without naming one.
Correction found on a second pass ("always populated" in go.md/java.md/python.md):
my first commit's Code-field descriptions said the machine-readable code is always populated.
True only for the 7 named error subclasses, each with its own default. The bare base error
returned for an unmapped HTTP status (an unexpected 5xx, for example) can have an empty/null
code: verified Go's defaultErrorCode() returns "" in its default case
(packages/go-sdk/http.go), Java's HttpClient.java falls through to new TurboDocxException(message, response.code(), code) with no fallback for the unmapped
case, and Python's base TurboDocxError class has DEFAULT_CODE = None
(packages/py-sdk/src/turbodocx_sdk/http.py). Qualified all three descriptions.
Broken links found and fixed (Docusaurus file-relative .md links resolve against the
linking file's directory and were left alone unless truly broken):
go.md and java.md linked to /docs/TurboSign/API-Signatures (hyphen); the real page is /docs/TurboSign/API Signatures.md, served at .../API%20Signatures (confirmed against
the other, correctly-encoded links in the same two files). Fixed both.
partner-php.md and partner-javascript.md linked to #orguserrole-organization-users, but
the actual heading is ### OrgUserRole (Organization Users and Org API Keys), which
Docusaurus slugifies to #orguserrole-organization-users-and-org-api-keys. Fixed both.
Frontmatter descriptions over 160 chars (11 files: agent-skills.md and all 5 quote-*/5 webhooks-* non-Ruby pages): rewritten to ≤137 chars, leading with the language
and product per the CONTENT SOP.
Noted, not fixed: docs/SDKs/ruby.md and deliverable-ruby.md (and the other three
Ruby product pages) 404 live but still get search impressions. Confirmed the removal was
intentional: git log origin/main -- docs/SDKs/ruby.md shows commit 40efd12 ("hide the
Ruby SDK pages until the gem is published") set draft: true on all five because turbodocx-sdk is not yet on RubyGems (still blocked per the SDK release-traps reference: no RUBYGEMS_API_KEY, gem 404s on RubyGems). Docusaurus excludes draft: true pages from the
production build entirely, so the 404s are by design, not an accident. Per the task's own
criterion, intentional removal that still draws impressions needs a redirect. The owner
picks the target and timing: javascript.md/python.md are the closest topical peers, but
both are also on the not-indexed list themselves, so neither is an obviously "safe" redirect
target either.
Out of scope, left as-is (no content changed, low content value, avoided disproportionate
diffs on files this CR did not otherwise touch):
The one-line :::caution API Credentials Required callout ("To get your credentials, follow
the Get Your Credentials steps...") repeated across 15 files, and the ## Resources → GitHub Repository footer repeated across 18 files. Both are short, functional
cross-reference text (already linking to the single canonical source rather than repeating
it) rather than templated content Google would flag.
Pre-existing em-dashes in quote-*.md/webhooks-*.md/agent-skills.md body content
(46-82 per file): this CR only touched their frontmatter description, and a full-file
em-dash sweep on content this task did not otherwise change would be a large, unrelated diff.
All prose actually added or edited by this CR is em-dash-free.
Template detector, before → after. The stock template-detector.mjs truncates its
5-gram report to the top 30 matches and its heading-strip regex fuses a heading straight into
the next paragraph (## Error Handling\n\nThe SDK provides... becomes one run-on "sentence"
for n-gram purposes), which understates the fix. Re-ran with an uncapped copy
(/home/nicolas/.claude/jobs/4fe2c970/tmp/template-detector-uncapped.mjs) that also strips
fenced code blocks and forces a sentence boundary after each heading, against both the
pre-change tree (git archive origin/develop) and the final result, counting the same 27
non-Ruby files on both sides:
Generic status-row wording (Invalid or missing API..., Invalid request parameters, Too many requests, Network connectivity issues): 15 files → 5 (verified by direct
grep: only go.md, java.md, javascript.md, php.md, python.md still carry it: five
per-language tables, wording intentionally shared across them, instead of duplicated
across 10 additional product pages too). The raw uncapped n-gram tool's per-phrase counts
land at 7-8 rather than exactly 5 because it scans all 32 files, including the 5 draft
Ruby pages this PR didn't touch, 3 of which still carry the same phrase
(grep -il "Invalid request parameters" docs/SDKs/*ruby*.md); the 27-file, non-Ruby grep
count is the number that matters and is 5.
Whole-directory uncapped total (every 5-gram shared by ≥3 files, all 32 files,
threshold 3): 5,494 → 5,388. That residue includes quote-*.md and webhooks-*.md,
disclosed below, plus the untouched draft Ruby pages and ordinary structural boilerplate
(table headers, MDX imports) that no rewrite eliminates.
The credentials callout and Resources footer counts (15 and 18 files) are unchanged by
design (see "out of scope" above); they're short, functional, already-canonicalized text.
Disclosed, not fixed: quote-*.md/webhooks-*.md still duplicate a per-product paragraph
across languages. Running the uncapped detector on just the 5 quote-*.md files (excluding
Ruby) finds 960 five-grams shared by all 5; on just the 5 webhooks-*.md files, 700 shared by
all 5. Some of that is unavoidable component boilerplate (<QuickstartSkillNudge .../>), but
part of it is real: quote-php.md, quote-python.md, and the draft quote-ruby.md open with
a byte-identical "What is TurboQuote?" paragraph, while quote-go.md and quote-javascript.md
already have distinct wording. quote-javascript.md and webhooks-java.md are themselves
evidence pages (crawled/discovered, not indexed) and got no body changes in this CR, only a
frontmatter description fix: this CR fixed the Error Handling duplication investigated first,
but the quote/webhooks product-intro duplication shown above is real and unaddressed here, not
something already covered. Rewriting the quote/webhooks per-language intros the way this CR
rewrote Error Handling is a legitimate follow-up; flagging as an owner question below rather
than expanding this CR further and risking a harder review.
Config check: re-read config/title-engineering.json per the owner's "playbook configs
win over TurboDocx SOP where they conflict" note. Its maxLength: 60 and number-first
guidance target page titles for listicle-style content; it has no description-length rule
and doesn't apply to SDK reference pages, so the ≤155-char description rewrites above don't
conflict with it.
Owner questions:
Ruby redirect: javascript.md or python.md as the target for ruby.md/ deliverable-ruby.md (and the other 3 Ruby pages), or leave the 404s until the gem ships?
Whether to do a follow-up pass on quote-*.md/webhooks-*.md rewriting the per-language
product-intro paragraphs the way this PR rewrote Error Handling (960 and 700 shared
5-grams respectively, see above), including the two remaining evidence pages quote-javascript.md and webhooks-java.md.
Not a docs issue, an SDK one: every one of the 5 SDKs leaves code empty/null for an error
on an HTTP status outside the 7 mapped ones (an unexpected 5xx, for example), even though
the Java javadoc for orDefault says code "must still be branchable" and is "kept
identical across all six SDKs." Worth a TurboDocx/SDK issue?
Component / area
Documentation: docs/SDKs/* (Go, PHP, Java, JavaScript/TypeScript, Python, and the
cross-language index.md)
Testing & validation
Re-ran template-detector.mjs (uncapped, before/after against origin/develop);
confirmed the flagged boilerplate is eliminated, cross-checked with direct grep since the
tool's own 30-match cap and heading/paragraph fusion were misleading on the first pass
Verified every changed code sample against the actual SDK source: read and cited packages/go-sdk/{http,deliverable,turbowebhooks}.go, packages/php-sdk/src/Exceptions/ {TurboDocxException,AuthorizationException,ConflictException}.php, packages/java-sdk/src/main/java/com/turbodocx/{TurboDocxException,TurboDocxClient, HttpClient}.java, packages/java-sdk/.../models/SendSignatureResponse.java, packages/js-sdk/src/utils/errors.ts, and packages/py-sdk/src/turbodocx_sdk/http.py
Verified the 5 deliverable-*.md claims about the generate-deliverable request body
against RapidDocxBackend/src/handlers/Deliverable/DeliverableGenerationHandlers.ts (its Variable interface: placeholder required, mimeType optional, the opposite of what an
earlier commit here claimed); confirmed that file is byte-identical to origin/staging
despite the local checkout being on feature/nscale-epic
Verified every changed/added link resolves to an existing file and heading slug with a
script that mirrors Docusaurus's github-slugger anchor algorithm
grep -c "—" returns 0 on every file this CR added or edited prose in (the 5 canonical
pages, the 10 deliverable/partner pages, index.md, go.md, java.md)
/home/nicolas/repos/SDK was checked out on feature/turbosign-embedded-identity
(unmerged SDK PR docs(turboquote): bulk spreadsheet import guide #77) while writing this; re-verified with git diff origin/main that the
5 source files actually cited above are byte-identical to origin/main, and confirmed no
branch-only symbol (createSigningUrl, getEmbeddedSigningSettings, identityVerification, embedded signing, OTP) appears anywhere in this PR's diff
Change type
Planned — normal review → merge
Risk / impact
Low
Security impact assessed?
No — no security impact
Details — description & full context
Trace task:
template-detector.mjs,config/anti-ai-rules.json, and the CONTENT SOP rulefor "Crawled - currently not indexed": de-duplicate before anything else.
Evidence: URL Inspection shows Google refusing to index substantial SDK pages:
docs/SDKs/javascript(4,186 words, crawled - not indexed),python,quote-javascript,webhooks-java,deliverable-go,deliverable-php(crawled - not indexed),java(discovered - not indexed).
template-detector.mjsfound the same 5-word phrases repeatedacross 15 of the 27 live (non-Ruby) SDK pages (a first pass with the tool's own reporting
quirks read this as ~17; see "Template detector" below), concentrated in a generic "Error
Handling" intro sentence plus a 7-row status-code table with identical English wording
(
Invalid or missing API key,Invalid request parameters,Too many requests,Network connectivity issues) copy-pasted regardless of language or product.queries.jsonshowsreal developer demand: "python digital signature sdk" (433 impressions, currently ranking on
the dotcom guide
/guides/sign-documents-with-python, not this docs page), "php digitalsignature sdk" (378, same pattern), "javascript pdf signature integration" (337, same
pattern). Data source:
queries.jsonwas generated byqueries.py, which calls the Google Search Console API directly(
searchAnalytics.queryonsc-domain:turbodocx.comvia agcloud auth application-default print-access-tokenbearer token), not PostHog's GSC warehouse tables;re-checked all three figures against the file directly before citing them here.
Root cause: two layers of duplication.
docs/SDKs/deliverable-{go,php,java,javascript,python}.mdanddocs/SDKs/partner-{go,php,java,javascript,python}.md(10 files) each carried a full copyof the generic error-type table that belongs, once, on that language's canonical page
(
javascript.md,python.md,go.md,php.md,java.md).quote-*.mdandwebhooks-*.mdhad no such generic error table to begin with; not part of this fix. (Theyhave their own, separate cross-language duplication in their product-intro paragraphs,
disclosed further down, unrelated to the error-table issue this fixes.)
## Error Handlingwith the identical sentence"The SDK provides typed error(s)/exception(s) for different ... scenarios", regardless of
language. Three of those five (
javascript.md,python.md,java.md) are themselvesevidence pages Google won't index.
Fix, part 1 (10 deliverable/partner pages): replaced the generic intro + table with a
short paragraph naming an error each operation actually raises (verified against
/home/nicolas/repos/SDK, e.g. Go'sNotFoundErroron an unknownTemplateID, PHP'sAuthenticationExceptionwhen the partner API key or partner ID is wrong), followed by alink to the language's own Error Handling reference for the full table. Kept the genuinely useful,
already-differentiated code samples (Go's
errors.As, PHP's typed exceptions, Java's nestedTurboDocxException.*classes, the partner-specificIOException/409-conflict notes).Fix, part 2 (5 canonical pages): rewrote each intro to state that language's real,
source-verified error-handling idiom instead of the shared sentence:
go.md: errors embedTurboDocxErrorby value; match witherrors.As, read fieldsdirectly (no getters). Added the
ConflictErrorrow/case that was missing from the table(it exists in
packages/go-sdk/http.gobut wasn't documented).php.md:statusCode/errorCodeare public readonly properties; PHP's inheritedException::getCode()is hardcoded to0by the constructor, so it never carries theerror code, a genuine footgun worth calling out. Added the
AuthorizationExceptionandConflictExceptionrows/catches that were missing (both exist inpackages/php-sdk/src/Exceptions/) but weren't documented, even thoughpartner-php.mdand
deliverable-php.mdalready referenced them.java.md: every exception is a nested static class ofTurboDocxException(
TurboDocxException.ValidationException, not a top-level import); each of the 7 namedsubclasses falls back to its own
DEFAULT_CODEvia a sharedorDefaulthelper(
TurboDocxException.java) sogetCode()is populated for those, though the bareTurboDocxExceptionthrown for an unmapped status has no such fallback.javascript.md:codeis a plain string the HTTP client passes through from the APIresponse when present (e.g.
QUOTE_NOT_FOUND) and only falls back to the class defaultotherwise, per the docstring in
packages/js-sdk/src/utils/errors.ts.python.md: every subclass sets its ownDEFAULT_CODEclass attribute(
packages/py-sdk/src/turbodocx_sdk/http.py); catch the most specific exception firstsince
except TurboDocxErroralso matches its subclasses.Bugs found while verifying code samples against SDK source, both in
index.md:$e->getCode(), but PHP'sException::getCode()ishardcoded to
0byTurboDocxException's constructor (parent::__construct($message, 0, $previous)inpackages/php-sdk/src/Exceptions/TurboDocxException.php); the real field isthe public readonly
$e->errorCode. Fixed.com.turbodocx.sdk.*(the SDK's real package iscom.turbodocx,no
.sdk), returned aSigningResulttype that doesn't exist in the SDK, and calledturboSign.sendSignature(...)on a bare variable instead of the actual builder pattern,client.turboSign().sendSignature(...). All three didn't matchjava.md's own correctexamples elsewhere in this same repo. Fixed to match; also added the
com.turbodocx.models.*importSendSignatureResponseneeds.errors.As(err, &turboErr)against*sdk.TurboDocxErroronly. Go'serrors.Asrequires the target's concrete type to match the error's;*sdk.ValidationError(and the 5 other named error types) is a distinct type from
*sdk.TurboDocxErroreventhough it embeds it, and neither implements
Unwrap/As, so this check silently failed tomatch any of the 6 named error types and only caught the generic unmapped-status case; the
VALIDATION_ERRORbranch shown in the example was dead code. Fixed to match*sdk.ValidationErrordirectly.e.message.TurboDocxError.__init__never setsself.message(nor does Python 3'sException), so this raisesAttributeErroratruntime. Fixed to
{e}(str(e)), matchingpython.md's own examples.codeis always populated" line just above these tabs had the same gap thelanguage-page correction below describes. Qualified it the same way.
Correction found on a second pass (5
deliverable-*.mdpages): my first commit claimedValidationErrorfires when a variable is missing "placeholderormimeType". CheckedRapidDocxBackend/src/handlers/Deliverable/DeliverableGenerationHandlers.ts: the actualVariableinterface used by the generate-deliverable request body hasplaceholder: string(required, no
?) butmimeType?: string(optional, has?), the opposite emphasis fromwhat I'd written. Couldn't find the runtime validation that actually rejects a missing
placeholder(the handler doesn't appear to check it before using it), so rather than assertan unverified 400, all 5 pages now say "missing a required field" without naming one.
Correction found on a second pass ("always populated" in
go.md/java.md/python.md):my first commit's Code-field descriptions said the machine-readable code is always populated.
True only for the 7 named error subclasses, each with its own default. The bare base error
returned for an unmapped HTTP status (an unexpected 5xx, for example) can have an empty/null
code: verified Go's
defaultErrorCode()returns""in its default case(
packages/go-sdk/http.go), Java'sHttpClient.javafalls through tonew TurboDocxException(message, response.code(), code)with no fallback for the unmappedcase, and Python's base
TurboDocxErrorclass hasDEFAULT_CODE = None(
packages/py-sdk/src/turbodocx_sdk/http.py). Qualified all three descriptions.Broken links found and fixed (Docusaurus file-relative
.mdlinks resolve against thelinking file's directory and were left alone unless truly broken):
go.mdandjava.mdlinked to/docs/TurboSign/API-Signatures(hyphen); the real page is/docs/TurboSign/API Signatures.md, served at.../API%20Signatures(confirmed againstthe other, correctly-encoded links in the same two files). Fixed both.
partner-php.mdandpartner-javascript.mdlinked to#orguserrole-organization-users, butthe actual heading is
### OrgUserRole (Organization Users and Org API Keys), whichDocusaurus slugifies to
#orguserrole-organization-users-and-org-api-keys. Fixed both.Frontmatter descriptions over 160 chars (11 files:
agent-skills.mdand all 5quote-*/5webhooks-*non-Ruby pages): rewritten to ≤137 chars, leading with the languageand product per the CONTENT SOP.
Noted, not fixed:
docs/SDKs/ruby.mdanddeliverable-ruby.md(and the other threeRuby product pages) 404 live but still get search impressions. Confirmed the removal was
intentional:
git log origin/main -- docs/SDKs/ruby.mdshows commit40efd12("hide theRuby SDK pages until the gem is published") set
draft: trueon all five becauseturbodocx-sdkis not yet on RubyGems (still blocked per the SDK release-traps reference: noRUBYGEMS_API_KEY, gem 404s on RubyGems). Docusaurus excludesdraft: truepages from theproduction build entirely, so the 404s are by design, not an accident. Per the task's own
criterion, intentional removal that still draws impressions needs a redirect. The owner
picks the target and timing:
javascript.md/python.mdare the closest topical peers, butboth are also on the not-indexed list themselves, so neither is an obviously "safe" redirect
target either.
Out of scope, left as-is (no content changed, low content value, avoided disproportionate
diffs on files this CR did not otherwise touch):
:::caution API Credentials Requiredcallout ("To get your credentials, followthe Get Your Credentials steps...") repeated across 15 files, and the
## Resources→GitHub Repositoryfooter repeated across 18 files. Both are short, functionalcross-reference text (already linking to the single canonical source rather than repeating
it) rather than templated content Google would flag.
quote-*.md/webhooks-*.md/agent-skills.mdbody content(46-82 per file): this CR only touched their frontmatter
description, and a full-fileem-dash sweep on content this task did not otherwise change would be a large, unrelated diff.
All prose actually added or edited by this CR is em-dash-free.
Template detector, before → after. The stock
template-detector.mjstruncates its5-gram report to the top 30 matches and its heading-strip regex fuses a heading straight into
the next paragraph (
## Error Handling\n\nThe SDK provides...becomes one run-on "sentence"for n-gram purposes), which understates the fix. Re-ran with an uncapped copy
(
/home/nicolas/.claude/jobs/4fe2c970/tmp/template-detector-uncapped.mjs) that also stripsfenced code blocks and forces a sentence boundary after each heading, against both the
pre-change tree (
git archive origin/develop) and the final result, counting the same 27non-Ruby files on both sides:
provides typed error(s)/provides typed exception(s)(the shared intro sentence):15 files → 0 (verified:
grep -il "provides typed" docs/SDKs/*.md, excluding the5 draft Ruby pages, returns nothing)
Invalid or missing API...,Invalid request parameters,Too many requests,Network connectivity issues): 15 files → 5 (verified by directgrep: only
go.md,java.md,javascript.md,php.md,python.mdstill carry it: fiveper-language tables, wording intentionally shared across them, instead of duplicated
across 10 additional product pages too). The raw uncapped n-gram tool's per-phrase counts
land at 7-8 rather than exactly 5 because it scans all 32 files, including the 5 draft
Ruby pages this PR didn't touch, 3 of which still carry the same phrase
(
grep -il "Invalid request parameters" docs/SDKs/*ruby*.md); the 27-file, non-Ruby grepcount is the number that matters and is 5.
threshold 3): 5,494 → 5,388. That residue includes
quote-*.mdandwebhooks-*.md,disclosed below, plus the untouched draft Ruby pages and ordinary structural boilerplate
(table headers, MDX imports) that no rewrite eliminates.
design (see "out of scope" above); they're short, functional, already-canonicalized text.
Disclosed, not fixed:
quote-*.md/webhooks-*.mdstill duplicate a per-product paragraphacross languages. Running the uncapped detector on just the 5
quote-*.mdfiles (excludingRuby) finds 960 five-grams shared by all 5; on just the 5
webhooks-*.mdfiles, 700 shared byall 5. Some of that is unavoidable component boilerplate (
<QuickstartSkillNudge .../>), butpart of it is real:
quote-php.md,quote-python.md, and the draftquote-ruby.mdopen witha byte-identical "What is TurboQuote?" paragraph, while
quote-go.mdandquote-javascript.mdalready have distinct wording.
quote-javascript.mdandwebhooks-java.mdare themselvesevidence pages (crawled/discovered, not indexed) and got no body changes in this CR, only a
frontmatter description fix: this CR fixed the Error Handling duplication investigated first,
but the quote/webhooks product-intro duplication shown above is real and unaddressed here, not
something already covered. Rewriting the quote/webhooks per-language intros the way this CR
rewrote Error Handling is a legitimate follow-up; flagging as an owner question below rather
than expanding this CR further and risking a harder review.
Config check: re-read
config/title-engineering.jsonper the owner's "playbook configswin over TurboDocx SOP where they conflict" note. Its
maxLength: 60and number-firstguidance target page titles for listicle-style content; it has no description-length rule
and doesn't apply to SDK reference pages, so the ≤155-char description rewrites above don't
conflict with it.
Owner questions:
javascript.mdorpython.mdas the target forruby.md/deliverable-ruby.md(and the other 3 Ruby pages), or leave the 404s until the gem ships?quote-*.md/webhooks-*.mdrewriting the per-languageproduct-intro paragraphs the way this PR rewrote Error Handling (960 and 700 shared
5-grams respectively, see above), including the two remaining evidence pages
quote-javascript.mdandwebhooks-java.md.codeempty/null for an erroron an HTTP status outside the 7 mapped ones (an unexpected 5xx, for example), even though
the Java javadoc for
orDefaultsays code "must still be branchable" and is "keptidentical across all six SDKs." Worth a TurboDocx/SDK issue?
Component / area
Documentation:
docs/SDKs/*(Go, PHP, Java, JavaScript/TypeScript, Python, and thecross-language
index.md)Testing & validation
template-detector.mjs(uncapped, before/after againstorigin/develop);confirmed the flagged boilerplate is eliminated, cross-checked with direct
grepsince thetool's own 30-match cap and heading/paragraph fusion were misleading on the first pass
packages/go-sdk/{http,deliverable,turbowebhooks}.go,packages/php-sdk/src/Exceptions/ {TurboDocxException,AuthorizationException,ConflictException}.php,packages/java-sdk/src/main/java/com/turbodocx/{TurboDocxException,TurboDocxClient, HttpClient}.java,packages/java-sdk/.../models/SendSignatureResponse.java,packages/js-sdk/src/utils/errors.ts, andpackages/py-sdk/src/turbodocx_sdk/http.pydeliverable-*.mdclaims about the generate-deliverable request bodyagainst
RapidDocxBackend/src/handlers/Deliverable/DeliverableGenerationHandlers.ts(itsVariableinterface:placeholderrequired,mimeTypeoptional, the opposite of what anearlier commit here claimed); confirmed that file is byte-identical to
origin/stagingdespite the local checkout being on
feature/nscale-epicscript that mirrors Docusaurus's
github-sluggeranchor algorithmgrep -c "—"returns 0 on every file this CR added or edited prose in (the 5 canonicalpages, the 10 deliverable/partner pages,
index.md,go.md,java.md)/home/nicolas/repos/SDKwas checked out onfeature/turbosign-embedded-identity(unmerged SDK PR docs(turboquote): bulk spreadsheet import guide #77) while writing this; re-verified with
git diff origin/mainthat the5 source files actually cited above are byte-identical to
origin/main, and confirmed nobranch-only symbol (
createSigningUrl,getEmbeddedSigningSettings,identityVerification, embedded signing, OTP) appears anywhere in this PR's diffRollback plan
Revert the merge commit.
Breaking change for consumers?
No
Reviewer / approver
A PR review approval satisfies this.