Community研究与数据分析github.com

Infinity-Technologies-Global/Infinity-ads-compliance-audit

name: infinity-ads-compliance-audit

Infinity-ads-compliance-audit 是什么?

Infinity-ads-compliance-audit is a Claude Code agent skill that name: infinity-ads-compliance-audit.

兼容平台Claude CodeCodex CLI~CursorAntigravityGemini CLI
npx skills add Infinity-Technologies-Global/Infinity-ads-compliance-audit

Installed? Explore more 研究与数据分析 skills: obra/superpowers, affaan-m/quarkus-verification, affaan-m/uspto-database · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Infinity Ads Compliance Audit

Audit an Android app against the Infinity ads base. The two supplied documents are the app-specific contract; the bundled references are the required architecture. Never claim a placement passes without evidence in the code.

The audit reads the project. It never modifies app source.

Inputs

Two documents, each either a local file or a Google Sheets/Docs share link:

DocumentCarries
ADS SCRIPTSplacement key, ad type, ad-unit ID, AdMob APP ID
working checklistapp name, package, Firebase project, Adjust/Facebook/TikTok tokens

Never substitute base IDs, and never audit with only one of the two.

Getting the documents — three tiers

Work down the tiers. Never skip to auditing because a document is hard to get.

Tier 1 — already in the project. Ask nothing. Two CSV files, one filename containing ADS SCRIPTS, one containing working or work file. The auditor discovers them itself. Just run it. Discovery refuses to guess when it finds zero or several candidates, which drops you to tier 2 or to an explicit path.

Tier 2 — not in the project and no link given. Ask, before running anything. Ask for both documents in one message, in the partner's language:

Gửi giúp mình 2 tài liệu: link Google Sheets/Docs của ADS SCRIPTS và của working checklist (để chế độ Bất kỳ ai có linkNgười xem). Hoặc tải sẵn 2 file CSV về máy rồi cho mình đường dẫn.

Ask for both at once, not one at a time. While waiting: do not run a partial audit, do not invent IDs, and do not fall back to the base project's values.

Tier 3 — a link was given but access is denied. The auditor stops with a sharing error. Relay both routes and let the partner pick:

  • Open the link → ShareGeneral accessAnyone with the link (Viewer), then tell you to rerun; or
  • Download it themselves — File → Download → Comma Separated Values (.csv) for a Sheet, Plain text (.txt) for a Doc — save it into the project folder, and give you the path. Rerun with that path in place of the link.

Both are equally valid. A downloaded CSV is often faster than getting sharing changed on a company Drive, so lead with that when the partner seems blocked.

Stop rule. If a document is still unavailable after tier 3, stop and report that the audit cannot start. An audit missing either contract document is not an audit — report that plainly rather than producing a partial result that reads like a verdict.

Run the audit

Resolve scripts/run_audit.py relative to the directory holding this SKILL.md. Skill locations differ per host — Claude Code (~/.claude/skills), Codex ($CODEX_HOME/skills, default ~/.codex/skills), Antigravity (~/.gemini/antigravity/skills) — so never assume a fixed path.

Run it yourself from the app root. Do not ask the partner to type commands.

python3 "/absolute/path/to/this-skill/scripts/run_audit.py" --project . \
  --base-project /home/infinity01/StudioProjects/TestSill

Both documents are auto-discovered from CSV files in the project. Pass them explicitly when discovery finds zero or several candidates, or when the partner gives you links:

python3 "/absolute/path/to/this-skill/scripts/run_audit.py" --project . \
  --ads-script   "https://docs.google.com/spreadsheets/d/<id>/edit#gid=0" \
  --working-file "https://docs.google.com/document/d/<id>/edit"

Links must be shared as anyone-with-the-link viewer. A sign-in page comes back as a sharing error, not as data. Explicit values always override discovery.

CSV layouts vary by partner. The parser prefers known aliases (Task Detail / Document, Content / Detail, Field / Value, and Vietnamese equivalents), then falls back to guarded content inference. If it reports an ambiguous layout, stop and ask for a clearer header — never guess between tied columns.

Then read ads-audit-output/ads-audit-summary.md and ads-audit-output/ads-audit-findings.json, and check every FAIL, NEEDS_MAPPING, and NEEDS_RUNTIME_PROOF against the actual code before reporting.

Reference material

  • base code reference — the real base implementation: Gradle setup, GlobalApp, AdsManager, every screen, gates, ad_config.json schema. Read this before judging whether code is correct.
  • base integration rules — the rules in checklist form.
  • placement mapping — approved class and call evidence per placement.

Required review scope

Follow the journey in order: Application → Splash → Language → Onboarding → Home/Banner → Resume/Welcome.

Initialization. GlobalApp.onCreate runs MobileAds.initializeDevConfig.initAdRemoteConfig.initializeFromAssetsERainAd.init, in that order. DevConfig.init receives the three BuildConfig version fields (the parameter is named nkhStudioVersion but takes ERAIN_STUDIO_VERSION). initAds sets environment, AdjustConfig, facebookClientToken, adjustTokenTiktok, intervalInterstitialAd = 35, idAdResume, the AppOpen exclusions, the lifecycle observer, and the activity callbacks. Secrets come from string resources, never inline literals.

Screen structure. Splash, Language, Onboarding, Home, and Welcome must be separate Activity classes. If any of them is a Fragment inside a single-Activity navigation graph, report ARCH_PRIMARY_SCREENS_ACTIVITY as FAIL and require migration. A Fragment used as a page inside one of those Activities — OnboardingPageFragment in a ViewPager2 — is correct base structure, not a violation.

Config. Every CSV key/ID exists in release ad_config.json and matches exactly. ad_config_debug.json is deliberately different and is never compared with the production contract. The AdMob app id comes from the release manifestPlaceholders; the debug block legitimately holds Google's test id.

Preload. Splash preloads the Language native only from the splash interstitial's onAdLoaded. Language preloads onboarding page 1 after its 100 ms postDelayed. Onboarding preloads native page 4, native full, and inter_onboarding after its own 100 ms delay. Moving a preload earlier or later changes fill rate and is a finding.

Load. Every native load goes through the central AdsManager helper with all four gates: isEnable, purchase, network, and the placement's getShouldDisplay*(config.enableUaCheck). On any refusal or failure the LiveData is set to null so the container hides. getShouldDisplayInterWelcomeBack lives in AppLifecycleObserver, not in AdsManager.

Show. Interstitials continue navigation only through the close/fail callback, and the show path always has an else { onAction() } so the user still advances when no ad is ready. The configured interval stays at 35 s.

Render. Natives observe a LiveData, call populateNativeAdView when non-null, and hide the container when null or offline. Fragments observe with viewLifecycleOwner. Language swaps between its two observers with removeObservers so both are never active at once.

Resume/Welcome. ResumeAdsEntryRule picks App Open or Welcome and they are mutually exclusive — open_resume wins when enabled — so an App Open ad and a Welcome interstitial never stack. AppLifecycleObserver applies the disabled-screen list, interstitial, purchase, and UA gates before routing to Welcome. Note the two exclusion lists differ: AppOpen excludes Splash/Language/OnBoarding/ConfirmUninstall; Welcome routing excludes Splash/Language/OnBoarding/Welcome/Survey.

Banner. BaseActivityWithBanner gates on isEnable, purchase, and the fr_banner container, honours reloadIntervalSeconds, and tears down its handler in onPause/onDestroy.

Unresolved items. A CSV placement with no approved class/event mapping stays NEEDS_MAPPING — neither pass nor failure. A user-event or lifecycle claim static analysis cannot settle stays NEEDS_RUNTIME_PROOF and must carry an executable test case.

Exceptions and new placements

For a class, event, or placement not inferable from the CSV, copy templates/ads-audit-overrides.yaml into the app and add an Infinity-approved mapping. Preserve the CSV key and ID exactly. A new key may differ from the base project, but its architecture must still follow the base pattern.

Reporting

The audit reports five areas of the ads journey, each Done or Error:

AreaCovers
InitGlobalApp init order, DevConfig fields, ERainAdConfig, AppOpen exclusions, interstitial interval, lifecycle observer registration
SplashRemoteConfig, inter_splash, banner_splash, open_resume, and the native-language preload from onAdLoaded
LanguageDevSetting, native click load, onboarding page-1 preload, observer swap with removeObservers, render and hide
OnboardingPreloads, page LiveData mapping, viewLifecycleOwner, and the interstitial before Home
ConfigRelease ad_config.json keys and IDs, AdMob app id, and coverage against the base's own key list

An area is Error only when it has a FAIL. NEEDS_MAPPING and NEEDS_RUNTIME_PROOF never turn an area red — they mean static analysis could not settle the claim, not that the app is wrong.

Failures outside the five areas — Welcome/Resume, Banner, service tokens, Firebase, direct SDK calls — are summarised in a single Note line. They still set the exit code to 2.

Three outputs:

  • ads-audit-output/ads-audit-summary.md — the five-area table plus each failure.
  • ads-audit-output/ads-audit-findings.json — every finding, for deep debugging.
  • One Discord message, and one row appended to the audit spreadsheet.

Discord

🚨 Ads Audit — My App
`com.example.app`

Init       → Done
Splash     → Done
Language   → Error: thiếu removeObservers
Onboarding → Done
Config     → Error: thiếu 3 key

Khác: banner chưa dùng BaseActivityWithBanner

Discord delivery is opt-in: provide --webhook-url, ADS_AUDIT_WEBHOOK_URL, or DISCORD_WEBHOOK_URL. Without one, the audit keeps only the local reports. Disable an inherited environment configuration with --no-webhook.

Audit spreadsheet

One row per audit: STT | Package | App name | Ngày | Init | Splash | Language | Onboarding | Config | Note.

The endpoint is embedded; the shared secret is not. In Apps Script, open Project Settings > Script Properties and add the required ADS_AUDIT_SHEET_TOKEN property. Give the auditor the same value through ADS_AUDIT_SHEET_TOKEN or --sheet-token; otherwise the push is skipped with a note on stderr. Disable with --no-sheet. templates/apps-script-sheet.gs is the receiving script and rejects every request when the property is absent.

Partner-facing result format

Reply in the partner's language, in this shape:

Init       → Done
Splash     → Done
Language   → Error: thiếu removeObservers
Onboarding → Done
Config     → Error: thiếu 3 key

Khác: <một dòng>

Add file:line for each Error only when the partner asks for detail. Never output raw Adjust, Facebook client, TikTok, webhook, or sheet secret values.

相关技能