Skip to content

ci(governance): allow Java in android/**/src/**/*.java (platform-required JVM shims)#341

Closed
hyperpolymath wants to merge 1 commit into
mainfrom
chore/android-java-shim-exemption
Closed

ci(governance): allow Java in android/**/src/**/*.java (platform-required JVM shims)#341
hyperpolymath wants to merge 1 commit into
mainfrom
chore/android-java-shim-exemption

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Why

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.

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 (the language-policy job's Java/Kotlin check). Tight regex (^|/)android/.*/src/.*\.java$; Kotlin (.kt, .kts) remains banned outright.

Properties

  • Tight scope. Only Java files inside an Android source tree.
  • Kotlin still fully banned.
  • Shim discipline. Each carve-out Java file is a minimal delegating wrapper that JNIs into Rust/Zig immediately. No business logic.
  • Matches existing layouts. Gossamer upstream's own gossamer/android/src/main/java/io/gossamer/... qualifies; neurophone's android/app/src/main/java/ai/neurophone/... qualifies.

Negative-space checks

  • Random Foo.java at repo root → blocked.
  • not-android/.../src/.../Foo.java → blocked.
  • android/Foo.java without src/ → blocked.
  • android/.../src/.../Foo.kt → blocked (Kotlin still in the ban list above the grep).

Fan-out after merge

  • 6 consumers pin @main → auto-consume (incl. neurophone itself).
  • 228 consumers pin SHA 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 files step (sub-PR #2 path 2B per the RFC) and rely on this estate-wide reusable as single source of truth.

Out of scope

  • Standards CLAUDE.md "Mobile Development" still lists "Tauri 2.0+" — estate pivoted to Gossamer per neurophone#97. Separate doc-update PR.
  • Java/Kotlin BANNED row in CLAUDE.md could note the carve-out — separate PR.

🤖 Generated with Claude Code

…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>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

🔍 Hypatia Security Scan

Findings: 201 issues detected

Severity Count
🔴 Critical 64
🟠 High 43
🟡 Medium 94

⚠️ Action Required: Critical security issues found!

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

@hyperpolymath
Copy link
Copy Markdown
Owner Author

Closing — the carve-out is already achievable via the existing .hypatia-baseline.json mechanism in this reusable (governance-reusable.yml:91-260 + is_exempt():292-305 + in_baseline():260-285).

Discovered after opening this PR: neurophone#105 (merged 2026-06-02T10:49:37Z) already added .hypatia-baseline.json with file_pattern: "android/**" to declare the carve-out per-consumer. The estate-wide reusable's language-policy job already honours that.

Why this PR is worse than the baseline path:

  • The grep -vE '(^|/)android/.*/src/.*\.java$' change is silent and global — any consumer can have Android Java without an explicit baseline declaration.
  • The baseline path requires each consumer to explicitly declare the carve-out, which is auditable (the baseline file is reviewable; the workflow grep change is invisible after merge).

A follow-up neurophone cleanup PR will remove the redundant LOCAL Check for Java/Kotlin files step (the baseline carve-out belongs upstream-only).

hyperpolymath added a commit to hyperpolymath/neurophone that referenced this pull request Jun 2, 2026
…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>
@hyperpolymath hyperpolymath deleted the chore/android-java-shim-exemption branch June 2, 2026 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant