05 — V8 Runtime Migration¶
This document is the V8-runtime component of the April 2026 upgrade plan. It is written to be read alongside Google's official Migrating scripts to the V8 runtime guide and is scoped specifically to the Adventive Looker Studio connector.
Why this is in the plan¶
Google is retiring the legacy Rhino runtime. Any Apps Script project that has not been migrated to the V8 runtime will stop executing on or after January 31, 2026. Google communicated the retirement timeline in February 2025 and has since distributed a CSV audit of every Apps Script project in each Workspace organization that may require manual conversion. The columns of that CSV are the basis for the triage checklist in this section.
Note on the deadline. The Rhino cutoff date (2026-01-31) has passed as of this plan's date (2026-04-22). If the production Adventive deployment is still on Rhino and has not been auto-migrated, it is already non-executing and every data request is failing at the platform layer — not in our code. The first validation step (below) determines which of those two states we are in.
What the CSV audit tells us¶
Google's CSV identifies every Apps Script project the organization owns and, for each, the columns that drive migration decisions. The ones that matter for this connector:
| Column | What to do with it |
|---|---|
Script_ID, Script_Url |
Identify the row that corresponds to our connector's Apps Script project |
Incompatibility_Reason |
If populated with "Incompatible Features Used" → we have to fix source code before V8 will run. If "Opted Out" → someone explicitly declined auto-migration; we must opt back in. If blank → the script was either auto-migrated or needs to be flipped manually (no code changes). |
Opted_Out |
"Yes" means the script was manually excluded from the automatic migration wave and will not run after the deadline unless we migrate it ourselves. |
Dependent_Library_Cnt |
Our connector has no Apps Script libraries bound; we expect 0. Verify. |
Dependency_Incompatibility_Reason |
Should be blank given the above. |
Is_Used_As_Library |
"No". The connector is consumed by Looker Studio, not imported by other Apps Scripts. |
Execution_Count |
Gives rough traffic shape over the prior 6 weeks — useful for estimating rollback blast-radius. |
The triage procedure below walks through these columns in order.
Triage procedure¶
- Locate the connector's row in the CSV by matching
Script_IDto the Script ID visible in Apps Script editor → Project Settings → Script ID. - Check
Opted_Out. No→ no manual opt-out was made. Continue.Yes→ someone on the Adventive side explicitly opted this script out of the automatic migration. Document who and why before proceeding; then treat the script as if it needs manual migration.- Check
Incompatibility_Reason. Incompatible Features Used→ the static analyzer flagged source features that V8 cannot execute. Work through the Incompatibility review section below before flipping the runtime.Opted Out→ same asOpted_Out = Yesabove.- Blank → the script is either compatible or already running on V8. Confirm which by reading
appscript.json→runtimeVersion. - Check
Dependent_Library_CntandIs_Used_As_Library. Both should be0/Nofor this connector. If either is non-zero, migration requires coordinating with the library's owner or consumers — out of scope for this plan; escalate. - Record current state in the migration log (link in Section 6): CSV row,
runtimeVersionvalue currently inappscript.json, and the timestamp of the check.
Incompatibility review — against this codebase¶
Google's V8 guide lists the Rhino-only features that V8 cannot execute. The table below scores each one against the connector's current source (Code.gs, Auth.gs, DataCache.gs).
| Incompatibility | Present in our code? | Action |
|---|---|---|
for each…in (JavaScript 1.6 iterator) |
No | None |
Date.prototype.getYear() (returns year minus 1900) |
No | None. The connector passes YYYYMMDD strings through; it does not construct Date objects. |
Reserved keywords used as identifiers (let, class, enum, etc.) |
No | None |
Reassigning const-declared variables |
No const is used today. |
None — but see Best practices below. |
XML literals / XML / XMLList object |
No | None |
__iterator__ custom iterators |
No | None |
Conditional catch clauses (catch (e if …)) |
No | None |
Object.prototype.toSource() |
No | None |
Error.fileName / Error.lineNumber access |
No | None |
for (var k in obj) used to iterate arrays (order changes under V8) |
getColumns uses for (var index in valuePaths) on an array — see note below |
Low risk; valuePaths has 1–2 elements. Refactor to a numeric for or forEach during the upgrade to avoid any future surprise. |
| Locale-specific date/time formatting | Not used | None |
| Stringified enum objects | Not used | None |
Net finding: the connector has no blocking incompatibility. The one cosmetic concern — iterating an array with for…in in getColumns — is a known V8 behavioural difference for arrays (enumeration order of integer-like string keys changed) and is harmless for a two-element array, but should be cleaned up in the same rewrite to prevent a future contributor from adding a property-named key that would enumerate in unexpected order.
Migration procedure — step by step¶
This procedure is written to be executed against the staging Apps Script project first, then promoted to production per §03 — Deployment & Management. Do not flip the runtime on production before completing steps 1–6 on staging.
- Verify the current runtime. In the Apps Script editor, check Project Settings → Show "appsscript.json" manifest file in editor. Open the manifest. If
runtimeVersionis"V8"the script is already on V8 — skip to step 4. If it is"DEPRECATED_ES5"(explicit Rhino) or the field is absent (implicit Rhino legacy), continue. - Take a versioned snapshot of the pre-migration state. In the editor, Deployments → Manage deployments → Archive does not apply here; instead, create a new version via
clasp version "pre-V8 snapshot $(date -u +%Y%m%d)"so the last known-good Rhino deployment can be rolled back to. Record the version number in the migration log. - Apply the code rewrite first, runtime flip second. The
connector-rewrite/files in this repository already set"runtimeVersion": "V8"inappscript.json. The recommended order is still two commits: - Commit 1: all the code-level fixes from §02, runtime unchanged.
- Commit 2: flip
runtimeVersionto"V8".
This separation makes it possible to bisect a failure to either the code fixes or the runtime flip if something breaks post-deploy.
4. clasp push the code-only commit to staging. Verify the connector authenticates and fetches data on the old runtime. This establishes that the remediation fixes in §02 did not themselves regress behaviour.
5. clasp push the runtime-flip commit. Re-run the verification checklist in §02 — this is what actually exercises V8 for the first time.
6. Create a versioned deployment with clasp deploy --description "v<X.Y.Z> — Migrate to V8 runtime". Record the new deployment ID in the migration log next to the pre-V8 snapshot's ID, so rollback is a one-command revert.
7. Promote to production using the standard deploy flow in §03. Do not skip the staging soak — 2 hours minimum.
8. Update the marketplace listing if the version displayed to users has changed (see §03 — Marketplace publishing).
9. Close the CSV row. In the migration log, mark the row as "Migrated — <version> on <date>" and attach the deployment ID.
Best practices adopted in this rewrite¶
These are improvements V8 enables. They are not mandatory for migration but are adopted in connector-rewrite/ where they improve clarity or safety without broadening the change surface.
- Keep
varacross the existing code paths. The rewrite does not convertvartolet/constwholesale. The reason is pragmatic: the function hoisting and scope behaviour ofvarinteracts with several existing closures inDataCache.gs, and rewriting those is code churn not justified by this migration's goal (make it run on V8). Future work can do avar → const/letsweep as a separate PR; doing it as part of the runtime migration makes diagnosis harder if something breaks. constfor top-level constants.API_CONNECTOR_URLandAPI_PING_URL— already hoisted out of theccglobal as part of QA-1 — remainvarin the rewrite for consistency with the rest of the file. A follow-up may promote them toconst.- Use
muteHttpExceptions: trueand explicit status checks rather than relying ontry/catcharound the HTTP call. V8 does not change this contract, but the change is safer on V8 because V8's error objects lackError.fileName/Error.lineNumberso the less we depend on stack-inspection, the more portable the code. - Avoid
for…inover arrays. The one instance ingetColumnswill be tightened during the rewrite to a numericforloop — see QA-5 in §02. - No
new Date().getYear()anywhere. None exists today; this is a standing rule for any future field that represents year-of-event.
Things to avoid when editing this connector on V8¶
The Google V8 guide calls these out and they are worth codifying as repo-level rules.
- Do not use
Date.prototype.getYear(). Always usegetFullYear(). On V8,getYear()returns year-minus-1900 (ECMAScript-compliant behaviour); on Rhino it returned the 4-digit year. Code written against the old Rhino behaviour silently breaks on V8. - Do not use
for each (var x in obj). This JavaScript 1.6 extension is a parse error under V8. - Do not use XML literals or the
XML/XMLListobjects. If the Adventive API ever starts returning XML and we need to parse it on-connector, useXmlService(Apps Script's built-in XML parser) — not the deprecated E4X literal syntax. - Do not add
__iterator__to any prototype. If a custom iterator is needed, use the ES6 iterator protocol ([Symbol.iterator]). - Do not use conditional catch clauses.
catch (e if cond)is Mozilla-only syntax and does not parse on V8. - Do not assign to a
const. Under Rhino this silently failed; under V8 it throwsTypeError. Pay attention if adoptingconstin future refactors. - Do not rely on
Error.fileNameorError.lineNumber. V8 does not populate these. Log the entiree.stackinstead. - Do not rely on
for (var k in arr)enumeration order for arrays. Use a numeric index orArray.prototype.forEach.
Rollback¶
If V8 surfaces a regression the runtime flip can be reverted independently of the code rewrite.
# From the repo root, with .clasp.json pointing at the affected environment:
git revert <sha-of-runtime-flip-commit> --no-edit
clasp push
clasp deploy --description "ROLLBACK: V8 → Rhino (reason: <short reason>)"
Hard caveat: a Rhino rollback is only valid before 2026-01-31 was Google's cutoff. If you are reading this after the Rhino runtime has been disabled platform-wide, the above rollback will succeed at the clasp layer but the reverted script will not execute when Looker Studio calls into it. The only forward path after the deadline is: identify the V8 regression, fix it, deploy a new V8 version. Keep this in mind before reaching for rollback as the first option.
Migration log template¶
Append one entry per environment. Store in the repository at docs/migration-log/v8-runtime.md.
Environment: staging / production
Script ID: <from apps script editor>
CSV row snapshot (date + relevant columns):
Incompatibility_Reason: <value>
Opted_Out: <value>
Dependent_Library_Cnt: <value>
Pre-V8 snapshot version: v<n> (clasp version number)
Pre-V8 deployment ID: <AKfyc…>
Post-V8 deployment ID: <AKfyc…>
Post-V8 clasp version: v<n+1>
Migrator: <engineer name + date>
Verification checklist: linked or attached
Regressions observed: none / <description>
Back to: README · Previous: 04 — Runbook