Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
- Goal-first BTrace observability skill suite with cloud/SRE workflows.
- Provider-neutral eval corpus and repository validation gate.
- `btrace-legacy-libs-migration` skill for moving retired `libs`/profile packaging into an extension.
- Moved `btrace-extensions-and-permissions` into `btrace-development`; extension authoring is build-time work, not incident diagnosis.
- `btrace-extension-authoring` skill for designing a new extension against a target library.
18 changes: 18 additions & 0 deletions evals/btrace-observability.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,5 +167,23 @@
"grantAll=true"
],
"rubric": "Recognise that libs= no longer loads anything and the missing classes are the symptom. Direct to one extension project with a single source set and declared services, not separate API and impl modules. Keep permission grants in permissions.properties rather than extensions.conf. Include verification by attaching and taking a trace."
},
{
"id": "extension-authoring-target-library",
"prompt": "I want to trace a third-party job scheduler library from BTrace. Its listener class is only on the application classpath and some methods only exist in newer versions. How should I structure the extension?",
"requiredSkills": [
"btrace-extension-authoring"
],
"mustMention": [
"Object",
"MethodHandleCache",
"Impl",
"version"
],
"mustAvoid": [
"publicLookup",
"grantAll=true"
],
"rubric": "Analyse before scaffolding. Keep target types out of the service signature and hand the object across as Object. Use @ExternalType only where the signature is nameable at compile time, and MethodHandleCache for version-variant members because its failures are not cached. Name the implementation <serviceFqcn>Impl or ship a provider declaration."
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: btrace-extension-authoring
description: Use when designing a new BTrace extension for a target library, framework, or runtime, deciding how a probe should reach target types safely, or choosing between @ExternalType and hand-written method handles.
---

# Extension Authoring

Start in analysis only. Establish which target entry points are public and stable, which versions
must be supported, and which types a probe actually needs, then say what the extension would look
like before creating any files. Report use of internal or version-sensitive target APIs as a risk
at this point rather than after scaffolding.

Derive the service surface from the probe-facing use cases, because everything downstream follows
from it. Service methods take and return only primitives, `java.*` types, and the extension's own
types; a target object crosses the boundary as `Object` and is resolved inside the implementation.
Keeping target types out of the service signature is what lets the extension load when the target
library is absent or a different version than expected.

Model an individual target type with `@ExternalType`, whose processor emits a companion adapter
with cached method handles. It fits a narrow shape: the whole signature must be nameable at
compile time, so any method that takes or returns a target-library type is out of reach; overloaded
names are rejected outright; fields, constructors, `instanceof`, and non-public members are not
supported; and members of packages a named module does not export are inaccessible. Check a target
method against that list before assuming the annotation can express it.

Note also that static dispatch resolves the owning class through the thread context class loader
while virtual dispatch uses the receiver's defining loader. Prefer virtual dispatch on a handed-off
receiver where a choice exists, because a context loader is whatever the application thread happens
to have set, and is frequently wrong under application servers, OSGi, and plugin loaders. Class
resolution is not cached, so a missing target class throws on every call rather than once, and it
surfaces at the probe call site rather than at load.

Use `ClassLoadingUtil` and `MethodHandleCache` for everything the annotation cannot express, and
for anything that varies across target versions. That cache stores successful lookups and never
stores failures, so catching a lookup failure is a genuine capability check that degrades to a
reduced feature set and recovers if the class appears later. `@ExternalType` offers no such catch
point, so version-variant members belong on the hand-written path.

Nothing in the metadata describes which target versions an extension supports; that is author
discipline. Because binding is per method and per class, a member missing from one version fails
only where it is used. Hand-written stubs of the target API under the test source set give unit
tests realistic fixtures and let a version matrix be exercised without the real dependency.

Name the implementation exactly `<serviceInterfaceFqcn>Impl`, or declare it in
`META-INF/services/<serviceInterfaceFqcn>`. Separating `api` and `impl` packages is reasonable and
requires the provider declaration, because the fallback is an exact name and nothing else. Extend
`Extension` when the service needs the extension context, initialization, or cleanup on detach; a
stateless service is better without it, since instantiation fails when no context is available.

Verify by inspecting the packaged artifacts, installing, attaching, and taking one trace that
exercises the injected service against the real target library rather than a stub.

Packaging mechanics, permission scanning, and the shared project layout are covered by
`btrace-extensions-and-permissions`. Fat agents for deployment are covered by the
`btrace-observability` plugin's startup and packaging guidance.
1 change: 0 additions & 1 deletion plugins/btrace-observability/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ All of these are bundled in this one plugin and may be combined for an incident:
| `btrace-runtime-access` | SSH, Docker, Kubernetes, sidecars, and cloud runtime boundaries. |
| `btrace-probe-lifecycle` | Attach, output capture, verification, reconnect, and removal. |
| `btrace-data-safety` | Sensitive output, production load, permissions, and scope escalation. |
| `btrace-extensions-and-permissions` | Metrics exporters, extensions, and minimal permission grants. |
| `btrace-mcp-operations` | Local BTrace MCP server workflows. |
| `btrace-startup-and-packaging` | Launch-time agents, fat agents, immutable images, and distroless workloads. |
| `btrace-legacy-libs-migration` | Retired `libs`/profile packaging, and moving it into an extension. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@ it into a no-op returning defaults and makes an unfinished migration look comple
fails, `btrace -le <PID>` reports why.

For deployments that cannot manage separate extension artifacts, load `btrace-startup-and-packaging`
for fat agents. For choosing permissions and deciding whether an extension is warranted at all,
load `btrace-extensions-and-permissions`.
for fat agents. Deciding whether an extension is warranted at all, and choosing its permissions, is
covered by the extension authoring guidance in the `btrace-development` plugin.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ and combine the specialist skills below as needed.
| Kubernetes, Docker, SSH, bastions, or cloud runtime access | `btrace-runtime-access` |
| Deploying, verifying, reconnecting, or stopping a probe | `btrace-probe-lifecycle` |
| Sensitive data, production load, permissions, or risk | `btrace-data-safety` |
| Extensions, metrics exporters, or permission grants | `btrace-extensions-and-permissions` |
| AI/MCP-guided local diagnostics | `btrace-mcp-operations` |
| Immutable images, no attach, or launch-time deployment | `btrace-startup-and-packaging` |
| Legacy `libs`/profile packaging that must become an extension | `btrace-legacy-libs-migration` |
Expand Down