Files
Naiyuan Qing aaedb864a0 refactor(diagnostics): drop the dead hang telemetry (MUL-5345) (#6433)
Two hang fields cost something and told us nothing, so both go.

HANG STACK CAPTURE. Shipped in v0.4.13, flag published since v0.4.14,
on in production — and every stack it produced was a single entry frame
with an empty url. `Debugger.pause` lands on the next JS statement
boundary, so when the block is in native code (layout, paint, GC, sync
IPC) or the pause dispatches just after the block clears, the frame we
get is the next function to run, not the one that blocked. It also only
fires for hard hangs, so it sampled a fraction of a signal that was
already useless. The price was a CDP debugger channel held open on every
renderer for the whole session.

The server key goes with it, and that is the part that matters for
already-installed clients: v0.4.13–v0.4.18 are fail-closed on this flag,
so no longer publishing `desktop_hang_stack_capture` is what makes them
stop attaching a debugger. keys_test now pins the key as unpublished —
re-adding it would put a flag flip back within reach of a fleet that
still can't produce a usable stack.

`recovered`. Hardcoded `false` at the only site that sets it. A
recovered hang has its breadcrumb cleared and is reported by the
in-thread watchdog instead, so the field could never be anything else.

A machine upgrading from v0.4.18 can still have a breadcrumb on disk
whose context holds a captured stack. `buildFreezeEventProps` builds
props by whitelist, so it drops on its own — pinned by a test, since
nothing sanitizes frames anymore.

What stays: the longtask watchdog, the main-unresponsive breadcrumb with
its bucketed route, client_crash, and $exception. Those are the signals
carrying the analysis in MUL-5345.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-08-05 16:36:51 +08:00

51 lines
2.0 KiB
Go

package featureflags
import (
"context"
"github.com/multica-ai/multica/server/pkg/featureflag"
)
const (
// ComposioMCPApps gates the Composio app management UI and — together with
// the MUL-3963 permission_mode / invocation_targets access model it depends
// on — the aligned Private / Public-to picker in the agent create flow.
// The access model exists to gate Composio sharing, so the two ship on the
// same switch.
ComposioMCPApps = "composio_mcp_apps"
// agentBuilderCompat is no longer a release flag. Keep publishing the key
// as enabled so installed desktop clients that still gate the AI creation
// entry on this config decision receive the permanently enabled behavior.
agentBuilderCompat = "agents_agent_builder"
// agentSkillTogglesCompat is no longer a release flag. Keep publishing the
// key as enabled so installed v0.4.0 desktop clients, which still gate the
// switch on this config decision, receive the permanently enabled behavior.
agentSkillTogglesCompat = "agents_skill_toggles"
// resourceLabelsCompat is no longer a release flag. Keep publishing the key
// as enabled for installed desktop clients from v0.4.0 through at least
// v0.4.15, every release shipped before this change. Unlike the skill-toggle
// gate above, which was removed client-side in v0.4.1, the resource-label
// gate remained in every such client and fails closed (default false) if
// the key stops being published.
resourceLabelsCompat = "settings_resource_labels"
)
var frontendPublicFlags = []string{
ComposioMCPApps,
}
func ComposioMCPAppsEnabled(ctx context.Context, flags *featureflag.Service) bool {
return flags.IsEnabled(ctx, ComposioMCPApps, false)
}
func EvaluateFrontendPublicFlags(ctx context.Context, flags *featureflag.Service) map[string]bool {
out := make(map[string]bool, len(frontendPublicFlags)+3)
for _, key := range frontendPublicFlags {
out[key] = flags.IsEnabled(ctx, key, false)
}
out[agentBuilderCompat] = true
out[agentSkillTogglesCompat] = true
out[resourceLabelsCompat] = true
return out
}