ci(governance): allow Java in android/**/src/**/*.java (platform-required JVM shims)#341
ci(governance): allow Java in android/**/src/**/*.java (platform-required JVM shims)#341hyperpolymath wants to merge 1 commit into
Conversation
…ired JVM shims) Android instantiates Service / BroadcastReceiver / AppWidgetProvider / Activity subclasses by class name at platform boundaries. The JVM classloader demands bytecode implementing those superclasses — Rust / Zig cannot satisfy this contract directly. Consumers writing mobile apps via Gossamer (or any webview shell) need a minimal Java shim surface that delegates immediately to native (JNI / Zig-FFI) code. This carve-out exempts EXACTLY `android/**/src/**/*.java` paths (anchored: `(^|/)android/.*/src/.*\.java$`). Properties: * `.kt` / `.kts` remain fully banned (no Kotlin carve-out). * Random `Foo.java` at repo root still fails. * `not-android/.../src/.../Foo.java` still fails. * Matches the established Android source-tree shape used by Gossamer upstream (`gossamer/android/src/main/java/io/gossamer/...`) and by consumers like neurophone (`android/app/src/main/java/ai/neurophone/...`). Triggered by the neurophone Kotlin → Gossamer migration RFC (hyperpolymath/neurophone#97). Without this carve-out the migration cannot land cleanly because the four JVM-class-name boundaries above are unavoidable. Each Java shim added under this carve-out must be a minimal delegating wrapper (typically <10 LoC) that JNIs into Rust/Zig immediately. The shim contains no business logic. No SHA bump required for the 6 consumers pinning `@main` (incl. neurophone). 228 consumers pinning SHA `861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613` will need a SHA-bump fan-out post-merge — coordinate via the established R5b campaign script. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 201 issues detected
View findings[
{
"reason": "Action for the check script)\n uses: actions/checkout@de0f needs attention",
"type": "unpinned_action",
"file": "governance-reusable.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action for the check script)\n uses: actions/checkout@de0f needs attention",
"type": "unpinned_action",
"file": "governance-reusable.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in affinescript-verify.yml",
"type": "missing_timeout_minutes",
"file": "affinescript-verify.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in boj-build.yml",
"type": "missing_timeout_minutes",
"file": "boj-build.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in casket-pages.yml",
"type": "missing_timeout_minutes",
"file": "casket-pages.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in casket-pages.yml",
"type": "missing_timeout_minutes",
"file": "casket-pages.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in changelog-reusable.yml",
"type": "missing_timeout_minutes",
"file": "changelog-reusable.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in codeql-reusable.yml",
"type": "missing_timeout_minutes",
"file": "codeql-reusable.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in codeql.yml",
"type": "missing_timeout_minutes",
"file": "codeql.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in deno-ci-reusable.yml",
"type": "missing_timeout_minutes",
"file": "deno-ci-reusable.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
|
Closing — the carve-out is already achievable via the existing Discovered after opening this PR: neurophone#105 (merged 2026-06-02T10:49:37Z) already added Why this PR is worse than the baseline path:
A follow-up neurophone cleanup PR will remove the redundant LOCAL |
…117) ## Why PR #105 added the android/** carve-out via **two** mechanisms: - (a) Prune `android/` from a local `find` step in `.github/workflows/language-policy.yml` - (b) Add `.hypatia-baseline.json` with `file_pattern: "android/**"` The estate-wide reusable at `hyperpolymath/standards/.github/workflows/governance-reusable.yml` (called from this repo's `governance.yml`) **already** reads `.hypatia-baseline.json` and exempts matched paths in its own `language-policy` job (see `governance-reusable.yml:91-285`). **(b) alone is sufficient.** (a) is a duplicate that uses the brittle `find` mechanism the reusable explicitly warns against — `git ls-files` respects `.gitignore` correctly. ## What this PR does Removes the local `Check for Java/Kotlin files` step. The neurophone `.hypatia-baseline.json` carve-out continues to handle the android/** exemption via the estate-wide reusable. ## Net behaviour change **Zero.** The local check duplicated the estate check. Both gate on Java/Kotlin files; both exempt android/** via different mechanisms. Removing the local check means there's one mechanism instead of two, and the remaining mechanism is the auditable baseline file. ## Properties preserved - Kotlin (`.kt`, `.kts`) is still fully banned — by the estate-wide reusable's `enforce "Java/Kotlin files"` block. - Non-Android Java (e.g. a stray `Foo.java` at repo root) is still blocked — same path. - The `android/**` carve-out is still respected via `.hypatia-baseline.json`. ## Stale-entry cleanup at end of migration When the Gossamer migration completes and `android/` is removed, the baseline entry will become stale. The reusable's `Detect stale baseline entries` job (`governance-reusable.yml:127+`) will warn. The entry can be removed in the same PR that deletes `android/` (i.e. sub-PR #9 of the migration sequence in RFC PR #97). ## Supersedes - `hyperpolymath/standards#341` (closed) — estate-wide grep change was redundant given the baseline mechanism already exists. - `#107` (closed) — same intent as this PR but pre-#105; rebase would have been a different change. ## Test plan - [x] Workflow YAML is well-formed (visually verified). - [ ] CI passes — local language-policy.yml runs without the Java/Kotlin step; estate-wide reusable runs and exempts android/** via baseline. - [ ] Negative test: a hypothetical `Foo.java` at repo root would still trigger the estate-wide `Language / package anti-pattern policy` job (verified by inspection of `governance-reusable.yml:345` + `enforce()` at line 310 + `is_exempt()` at line 292). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Why
Android instantiates
Service/BroadcastReceiver/AppWidgetProvider/Activitysubclasses by class name at platform boundaries. The JVM classloader demands bytecode implementing those superclasses — Rust / Zig cannot satisfy this contract directly. Consumers writing mobile apps via Gossamer (or any webview shell) need a minimal Java shim surface that delegates immediately to native (JNI / Zig-FFI) code.Triggered by neurophone#97 (Kotlin → Gossamer migration RFC). Without this carve-out the migration cannot land cleanly.
What changes
One block in
governance-reusable.yml(thelanguage-policyjob's Java/Kotlin check). Tight regex(^|/)android/.*/src/.*\.java$; Kotlin (.kt,.kts) remains banned outright.Properties
gossamer/android/src/main/java/io/gossamer/...qualifies; neurophone'sandroid/app/src/main/java/ai/neurophone/...qualifies.Negative-space checks
Foo.javaat repo root → blocked.not-android/.../src/.../Foo.java→ blocked.android/Foo.javawithoutsrc/→ blocked.android/.../src/.../Foo.kt→ blocked (Kotlin still in the ban list above the grep).Fan-out after merge
@main→ auto-consume (incl. neurophone itself).861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613→ SHA-bump fan-out needed; coordinate via R5b campaign script.Companion change
Separate neurophone PR will delete neurophone's local
Check for Java/Kotlin filesstep (sub-PR #2 path 2B per the RFC) and rely on this estate-wide reusable as single source of truth.Out of scope
🤖 Generated with Claude Code