@barefootjs/jsx 0.15.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -183,8 +183,8 @@ export { isLowerableObjectRestDestructure } from './loop-destructure.ts';
183
183
  export { buildComponentGraph, buildComponentAnalysis, buildGraphFromIR, buildEventSummary, buildLoopSummary, buildWhyUpdate, traceUpdatePath, formatComponentGraph, formatUpdatePath, formatEventSummary, formatLoopSummary, formatWhyUpdate, describeFallback, formatFallbackExplanations, buildComponentSummary, formatComponentSummary, formatSignalTrace, generateStaticTrace, graphToJSON, resolveSetters, buildLocalFunctionSetterMap, makeIdCallRegex, } from './debug.ts';
184
184
  export type { ComponentGraph, ComponentAnalysis, SignalNode, MemoNode, EffectNode, DomBinding, UpdatePath, SignalTrace, EventBinding, SetterRef, FnSetterResolution, EventSummary, LoopInfo, LoopChildBinding, LoopSummary, WhyUpdateResult, WhyUpdateDep, WhyUpdateSource, FallbackExplanation, ComponentSummary } from './debug.ts';
185
185
  export type { WrapReason } from './ir-to-client-js/reactivity.ts';
186
- export { PROFILE_SCHEMA_VERSION, buildStaticBudget, formatStaticBudget, diffStaticBudget, formatBudgetDiff, buildProfileReport, formatProfileReport, buildIdIndex, joinProfilerEvents, parseProfilerId, analyzeHotSubscribers, formatHotSubscribers, findUninstrumentedEffects, analyzeWastedReReruns, formatWastedReReruns, analyzeBatchAdvisor, formatBatchAdvisor, } from './profiler.ts';
187
- export type { StaticBudget, StaticBudgetOptions, FanOutEntry, BudgetHandler, BudgetDiff, FanOutChange, ProfileReport, ProfileReportInput, ProfileCoverage, DiagnosticsSummary, EffectCandidate, IdIndex, ResolvedNode, JoinResult, JoinedEvent, UnattributedId, HotSubscribersResult, HotSubscriber, HotSubscribersOptions, WastedReRunsResult, WastedSubscriber, WastedReRunsOptions, BatchAdvisorResult, BatchCandidate, BatchSafety, } from './profiler.ts';
186
+ export { PROFILE_SCHEMA_VERSION, buildStaticBudget, formatStaticBudget, diffStaticBudget, formatBudgetDiff, buildProfileReport, formatProfileReport, buildIdIndex, joinProfilerEvents, parseProfilerId, analyzeHotSubscribers, formatHotSubscribers, findUninstrumentedEffects, analyzeWastedReReruns, formatWastedReReruns, analyzeBatchAdvisor, formatBatchAdvisor, evaluateProfileGates, } from './profiler.ts';
187
+ export type { StaticBudget, StaticBudgetOptions, FanOutEntry, BudgetHandler, BudgetDiff, FanOutChange, ProfileReport, ProfileReportInput, ProfileCoverage, DiagnosticsSummary, EffectCandidate, IdIndex, ResolvedNode, JoinResult, JoinedEvent, UnattributedId, HotSubscribersResult, HotSubscriber, HotSubscribersOptions, WastedReRunsResult, WastedSubscriber, WastedReRunsOptions, BatchAdvisorResult, BatchCandidate, BatchSafety, ProfileSeverity, ProfileStatus, AgentFinding, ScenarioGuidance, GateName, GateConfig, GateCheck, GateResult, } from './profiler.ts';
188
188
  export { buildReactiveProfile, buildProfileFromGraph, diffProfiles, formatSingleProfile, formatProfileTable, formatProfileDiff, profileToJSON, } from './debug-profile.ts';
189
189
  export type { ComponentProfile, ComponentProfileMetrics, ProfileFinding, ProfileDiff, ProfileDiffEntry, } from './debug-profile.ts';
190
190
  export { BOOLEAN_ATTRS, isBooleanAttr } from './html-constants.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -20725,6 +20725,71 @@ function turnToEventBinding(graph, events) {
20725
20725
  }
20726
20726
  return out;
20727
20727
  }
20728
+ function nextCommandsForSubscriber(fallbackComponent, subscriber) {
20729
+ const cmds = [];
20730
+ const parsed = parseProfilerId(subscriber);
20731
+ const component = parsed?.component ?? fallbackComponent;
20732
+ if (parsed) {
20733
+ if (parsed.kind === "memo" || parsed.kind === "signal") {
20734
+ cmds.push(`bf debug trace ${component} ${parsed.rest} --json`);
20735
+ } else if (parsed.kind === "binding") {
20736
+ cmds.push(`bf debug why-update ${component} ${parsed.rest} --json`);
20737
+ }
20738
+ }
20739
+ cmds.push(`bf debug graph ${component} --json`);
20740
+ return cmds;
20741
+ }
20742
+ function buildAgentFindings(component, hotSubscribers, wastedReReruns, batchAdvisor, unattributed) {
20743
+ const findings = [];
20744
+ for (const s of hotSubscribers.subscribers) {
20745
+ if (!s.hot)
20746
+ continue;
20747
+ findings.push({
20748
+ kind: "hot-subscriber",
20749
+ severity: "warning",
20750
+ actionable: s.loc !== undefined,
20751
+ subscriber: s.subscriber,
20752
+ loc: s.loc,
20753
+ message: `${s.name ?? s.subscriber} ran ${s.runsPerTurn.toFixed(1)}×/turn — re-run pressure (split or batch).`,
20754
+ nextCommands: nextCommandsForSubscriber(component, s.subscriber)
20755
+ });
20756
+ }
20757
+ for (const s of wastedReReruns.subscribers) {
20758
+ if (!s.wasted)
20759
+ continue;
20760
+ findings.push({
20761
+ kind: "wasted-re-run",
20762
+ severity: "warning",
20763
+ actionable: s.loc !== undefined,
20764
+ subscriber: s.subscriber,
20765
+ loc: s.loc,
20766
+ message: `${s.name ?? s.subscriber} produced identical output in ${Math.round(s.wastedRatio * 100)}% of runs — finer split.`,
20767
+ nextCommands: nextCommandsForSubscriber(component, s.subscriber)
20768
+ });
20769
+ }
20770
+ for (const c of batchAdvisor.candidates) {
20771
+ findings.push({
20772
+ kind: "batch-candidate",
20773
+ severity: c.safety === "safe" ? "warning" : "info",
20774
+ actionable: c.safety === "safe" && c.loc !== undefined,
20775
+ subscriber: c.turn,
20776
+ loc: c.loc,
20777
+ message: `${c.handler ?? c.turn} re-ran shared effects ${c.savings}× extra across ${c.writes} writes — batch() candidate (${c.safety}).`,
20778
+ nextCommands: nextCommandsForSubscriber(component, c.turn)
20779
+ });
20780
+ }
20781
+ for (const u of unattributed) {
20782
+ findings.push({
20783
+ kind: "coverage-gap",
20784
+ severity: "warning",
20785
+ actionable: true,
20786
+ subscriber: u.id,
20787
+ message: `Unresolved subscriber id "${u.id}" — could not map to source (scope caveat).`,
20788
+ nextCommands: nextCommandsForSubscriber(component, u.id)
20789
+ });
20790
+ }
20791
+ return findings;
20792
+ }
20728
20793
  function buildProfileReport(input) {
20729
20794
  const { source, filePath, componentName, scenario, events } = input;
20730
20795
  const primary = buildComponentAnalysis(source, filePath, componentName).graph;
@@ -20801,6 +20866,27 @@ function buildProfileReport(input) {
20801
20866
  handlerIds.add(e.turn);
20802
20867
  }
20803
20868
  }
20869
+ const findings = buildAgentFindings(primary.componentName, hotSubscribers, wastedReReruns, batchAdvisor, unattributed);
20870
+ const status = findings.some((f) => f.severity === "warning" || f.severity === "error") ? "warning" : "ok";
20871
+ const ratio = handlersTotal > 0 ? Math.min(1, handlerIds.size / handlersTotal) : 1;
20872
+ let guidance;
20873
+ if (turnSeqs.size === 0) {
20874
+ guidance = handlersTotal === 0 ? {
20875
+ reason: "no-handlers",
20876
+ message: "No event handlers — use the static budget instead of a dynamic run.",
20877
+ nextCommands: [`bf debug profile ${primary.componentName} --json`]
20878
+ } : {
20879
+ reason: "no-interactions",
20880
+ message: "Handlers exist but none fired — they likely live in composed children. Drive the component with a story/scenario file.",
20881
+ nextCommands: [`bf debug profile ${primary.componentName} --scenario <story.tsx> --json`]
20882
+ };
20883
+ } else if (ratio < 1) {
20884
+ guidance = {
20885
+ reason: "partial-coverage",
20886
+ message: `Only ${handlerIds.size}/${handlersTotal} handlers exercised — a story/scenario file can cover the rest.`,
20887
+ nextCommands: [`bf debug profile ${primary.componentName} --scenario <story.tsx> --json`]
20888
+ };
20889
+ }
20804
20890
  return {
20805
20891
  kind: "profile",
20806
20892
  schemaVersion: PROFILE_SCHEMA_VERSION,
@@ -20815,9 +20901,13 @@ function buildProfileReport(input) {
20815
20901
  coverage: {
20816
20902
  handlersFired: handlerIds.size,
20817
20903
  handlersTotal,
20904
+ ratio,
20818
20905
  unattributed,
20819
20906
  diagnostics: { count: diagnostics.length, sample: diagnostics.slice(0, 3).map((d) => d.id) }
20820
- }
20907
+ },
20908
+ status,
20909
+ findings,
20910
+ ...guidance ? { guidance } : {}
20821
20911
  };
20822
20912
  }
20823
20913
  function formatProfileReport(r) {
@@ -20842,9 +20932,67 @@ function formatProfileReport(r) {
20842
20932
  if (c.diagnostics.count > 0) {
20843
20933
  lines.push(` · ${c.diagnostics.count} anonymous runtime id(s) (non-actionable bookkeeping)`);
20844
20934
  }
20935
+ lines.push("");
20936
+ lines.push(`status: ${r.status} (${r.findings.length} finding(s))`);
20937
+ if (r.guidance) {
20938
+ lines.push(` guidance: ${r.guidance.message}`);
20939
+ lines.push(` next: ${r.guidance.nextCommands[0]}`);
20940
+ } else if (r.findings.length > 0) {
20941
+ lines.push(` next: ${r.findings[0].nextCommands[0]}`);
20942
+ }
20845
20943
  return lines.join(`
20846
20944
  `);
20847
20945
  }
20946
+ function evaluateProfileGates(report, config) {
20947
+ const failOn = new Set(config.failOn ?? []);
20948
+ const checks = [];
20949
+ if (failOn.has("coverage") || config.minCoverage !== undefined) {
20950
+ const threshold = config.minCoverage ?? 1;
20951
+ const observed = report.coverage.ratio;
20952
+ checks.push({
20953
+ gate: "coverage",
20954
+ passed: observed >= threshold,
20955
+ observed,
20956
+ threshold,
20957
+ message: `coverage ${(observed * 100).toFixed(0)}% ${observed >= threshold ? "≥" : "<"} required ${(threshold * 100).toFixed(0)}%`
20958
+ });
20959
+ }
20960
+ if (failOn.has("unresolved") || config.maxUnresolved !== undefined) {
20961
+ const threshold = config.maxUnresolved ?? 0;
20962
+ const observed = report.coverage.unattributed.length;
20963
+ checks.push({
20964
+ gate: "unresolved",
20965
+ passed: observed <= threshold,
20966
+ observed,
20967
+ threshold,
20968
+ message: `${observed} unresolved id(s) ${observed <= threshold ? "≤" : ">"} allowed ${threshold}`
20969
+ });
20970
+ }
20971
+ if (failOn.has("hot") || config.maxRunsPerTurn !== undefined) {
20972
+ const observed = report.hotSubscribers.subscribers.reduce((m, s) => Math.max(m, s.runsPerTurn), 0);
20973
+ if (config.maxRunsPerTurn !== undefined) {
20974
+ const threshold = config.maxRunsPerTurn;
20975
+ checks.push({
20976
+ gate: "hot",
20977
+ passed: observed <= threshold,
20978
+ observed,
20979
+ threshold,
20980
+ message: `max ${observed.toFixed(1)} runs/turn ${observed <= threshold ? "≤" : ">"} budget ${threshold}`
20981
+ });
20982
+ } else {
20983
+ const anyHot = report.hotSubscribers.subscribers.some((s) => s.hot);
20984
+ checks.push({
20985
+ gate: "hot",
20986
+ passed: !anyHot,
20987
+ observed,
20988
+ threshold: null,
20989
+ message: anyHot ? `hot subscriber(s) present (max ${observed.toFixed(1)} runs/turn)` : "no hot subscribers"
20990
+ });
20991
+ }
20992
+ }
20993
+ const failed = checks.filter((c) => !c.passed).map((c) => c.gate);
20994
+ return { passed: failed.length === 0, failed, checks };
20995
+ }
20848
20996
  // src/debug-profile.ts
20849
20997
  var THRESHOLDS = {
20850
20998
  highFanOut: 3,
@@ -21572,6 +21720,7 @@ export {
21572
21720
  extractFunctionParams,
21573
21721
  extractArrowBodyExpression,
21574
21722
  exprToString,
21723
+ evaluateProfileGates,
21575
21724
  evalStringArrayJoin,
21576
21725
  enableCompilerInstrumentation,
21577
21726
  emitParsedExpr,
@@ -476,6 +476,13 @@ export interface ProfileCoverage {
476
476
  handlersFired: number;
477
477
  /** Handlers the IR knows about (`buildEventSummary`). */
478
478
  handlersTotal: number;
479
+ /**
480
+ * `handlersFired / handlersTotal` in `[0,1]` — the fraction of known handlers
481
+ * this run exercised, so an agent can gate on it (`--min-coverage`) without
482
+ * dividing the two counts itself (#1841). `1` when the component has no
483
+ * handlers (nothing to cover ⇒ trivially complete, not a gap).
484
+ */
485
+ ratio: number;
479
486
  /** SR4 ids the IR could not resolve — the honest, actionable gap. */
480
487
  unattributed: UnattributedId[];
481
488
  /**
@@ -501,6 +508,76 @@ export interface ProfileReport {
501
508
  wastedReReruns: WastedReRunsResult;
502
509
  batchAdvisor: BatchAdvisorResult;
503
510
  coverage: ProfileCoverage;
511
+ /**
512
+ * Normalized run status an agent can branch on without parsing prose (#1841):
513
+ * `ok` when nothing is flagged, `warning` when any finding is severity
514
+ * `warning` or higher — regardless of its `actionable` flag, since an
515
+ * unresolved-but-real cost (e.g. a hot subscriber with no source loc) is still
516
+ * worth surfacing. A failed *gate* escalates this to `error` — but gates are
517
+ * policy applied by the CLI from flags, so the builder only ever sets
518
+ * `ok`/`warning` here.
519
+ */
520
+ status: ProfileStatus;
521
+ /**
522
+ * Flattened, normalized findings (#1841): the hot/wasted/batch/coverage tables
523
+ * re-expressed with a single `severity` scale, an explicit `actionable` flag,
524
+ * and `nextCommands` — the exact follow-up `bf debug …` invocations to run.
525
+ * The structured tables above stay the source of truth; this is the agent view.
526
+ */
527
+ findings: AgentFinding[];
528
+ /**
529
+ * Coverage guidance for an under-exercised run (#1841): present only when the
530
+ * scenario fired no or only some handlers, which usually means a story file is
531
+ * needed (handlers live in composed children).
532
+ */
533
+ guidance?: ScenarioGuidance;
534
+ }
535
+ /** Normalized finding severity an agent can branch on without parsing prose. */
536
+ export type ProfileSeverity = 'info' | 'warning' | 'error';
537
+ /** Top-level run status: `ok` (clean), `warning` (findings), `error` (gate failed). */
538
+ export type ProfileStatus = 'ok' | 'warning' | 'error';
539
+ /**
540
+ * One normalized, machine-actionable finding flattened from the per-analysis
541
+ * tables (hot subscribers / wasted re-runs / batch advisor / coverage gaps).
542
+ * Carries the agent contract fields the issue asks for: a normalized `severity`,
543
+ * an explicit `actionable` flag (`false` ⇒ no safe direct fix — e.g. an
544
+ * unverified advisory), and `nextCommands` — valid, ready-to-run `bf debug …`
545
+ * follow-ups.
546
+ */
547
+ export interface AgentFinding {
548
+ kind: 'hot-subscriber' | 'wasted-re-run' | 'batch-candidate' | 'coverage-gap';
549
+ severity: ProfileSeverity;
550
+ /**
551
+ * Whether this finding has a concrete fix worth acting on directly. `false`
552
+ * marks a finding an agent should *not* apply blindly — an unverified `batch()`
553
+ * advisory (the wrap could change behavior) or a finding whose source location
554
+ * the id index couldn't resolve. A coverage gap is `actionable: true`: the next
555
+ * step (widen the scenario, inspect the graph) is clear even without a `loc`.
556
+ */
557
+ actionable: boolean;
558
+ /** The compiler subscriber/turn id this finding is about, when it has one. */
559
+ subscriber?: string;
560
+ /** Source location, when the id resolved to an IR node. */
561
+ loc?: {
562
+ file: string;
563
+ line: number;
564
+ };
565
+ /** One-line human summary — the same sentence the text report would print. */
566
+ message: string;
567
+ /** Follow-up commands to run next — valid, ready-to-run `bf debug …` lines. */
568
+ nextCommands: string[];
569
+ }
570
+ /**
571
+ * Coverage guidance for an under-exercised run (#1841). `--scenario auto` can
572
+ * only fire handlers the IR exposes on *this* component; for a compound/context
573
+ * component whose handlers live in composed children it fires `0/N`, and the
574
+ * honest next step is a story/scenario file rather than trusting a thin run.
575
+ */
576
+ export interface ScenarioGuidance {
577
+ /** Why coverage was incomplete — drives the suggested next step. */
578
+ reason: 'no-handlers' | 'no-interactions' | 'partial-coverage';
579
+ message: string;
580
+ nextCommands: string[];
504
581
  }
505
582
  export interface ProfileReportInput {
506
583
  source: string;
@@ -536,4 +613,42 @@ export interface ProfileReportInput {
536
613
  */
537
614
  export declare function buildProfileReport(input: ProfileReportInput): ProfileReport;
538
615
  export declare function formatProfileReport(r: ProfileReport): string;
616
+ /** The gate names `--fail-on` accepts. `regression` applies to `--diff` mode. */
617
+ export type GateName = 'unresolved' | 'hot' | 'coverage' | 'regression';
618
+ /**
619
+ * Gate thresholds an agent/CI supplies via flags. A gate is *active* when it is
620
+ * named in `failOn` or its numeric threshold is set — so `--max-unresolved 0`
621
+ * enforces the unresolved gate without also passing `--fail-on unresolved`.
622
+ */
623
+ export interface GateConfig {
624
+ failOn?: readonly GateName[];
625
+ /** `--min-coverage`: minimum `coverage.ratio` in `[0,1]`. */
626
+ minCoverage?: number;
627
+ /** `--max-runs-per-turn`: budget for the hottest subscriber's runs/turn. */
628
+ maxRunsPerTurn?: number;
629
+ /** `--max-unresolved`: maximum allowed unresolved (actionable) coverage gaps. */
630
+ maxUnresolved?: number;
631
+ }
632
+ export interface GateCheck {
633
+ gate: GateName;
634
+ passed: boolean;
635
+ /** The measured value the gate compared (ratio, count, or runs/turn). */
636
+ observed: number;
637
+ /** The threshold it was compared against; `null` for a boolean gate. */
638
+ threshold: number | null;
639
+ message: string;
640
+ }
641
+ export interface GateResult {
642
+ passed: boolean;
643
+ /** Names of the gates that failed — the `gates.failed` an agent branches on. */
644
+ failed: GateName[];
645
+ checks: GateCheck[];
646
+ }
647
+ /**
648
+ * Evaluate the dynamic-run gates (#1841) against a measured report. Pure: maps a
649
+ * `ProfileReport` + thresholds to a pass/fail decision the CLI turns into an
650
+ * exit code. The `regression` gate is *not* evaluated here — it belongs to
651
+ * `--diff` mode, which the CLI gates directly off the `BudgetDiff`.
652
+ */
653
+ export declare function evaluateProfileGates(report: ProfileReport, config: GateConfig): GateResult;
539
654
  //# sourceMappingURL=profiler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../src/profiler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../src/profiler.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/jsx",
3
- "version": "0.15.2",
3
+ "version": "0.16.0",
4
4
  "description": "JSX compiler for BarefootJS - transforms JSX to server HTML + client JS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -53,7 +53,7 @@
53
53
  "directory": "packages/jsx"
54
54
  },
55
55
  "dependencies": {
56
- "@barefootjs/shared": "0.15.2"
56
+ "@barefootjs/shared": "0.16.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@barefootjs/client": ">=0.2.0",
@@ -20,6 +20,7 @@ import {
20
20
  buildIdIndex,
21
21
  joinProfilerEvents,
22
22
  findUninstrumentedEffects,
23
+ evaluateProfileGates,
23
24
  } from '../profiler'
24
25
  import { buildComponentAnalysis } from '../debug'
25
26
  import type { ProfilerEvent } from '@barefootjs/shared'
@@ -533,3 +534,151 @@ describe('findUninstrumentedEffects (#1849 B6)', () => {
533
534
  expect(e1.candidates).toEqual([{ file: 'C.tsx', line: 8 }])
534
535
  })
535
536
  })
537
+
538
+ describe('agent contract: status, findings, guidance (#1841)', () => {
539
+ const src = `
540
+ 'use client'
541
+ import { createSignal, createMemo } from '@barefootjs/client'
542
+ export function Calc() {
543
+ const [count, setCount] = createSignal(0)
544
+ const a = createMemo(() => count() * 2)
545
+ return <button onClick={() => setCount(count() + 1)}>{a()}</button>
546
+ }
547
+ `
548
+ let n = 0
549
+ const ev = (type: ProfilerEvent['type'], f: Partial<ProfilerEvent> = {}): ProfilerEvent =>
550
+ ({ type, seq: n++, turn: null, ...f })
551
+
552
+ // A memo that re-runs 3× in a single turn → runsPerTurn 3 → flagged `hot`.
553
+ function hotRunEvents(): ProfilerEvent[] {
554
+ n = 0
555
+ const turn = 'Calc#handler:s0:click'
556
+ const events: ProfilerEvent[] = [ev('turnBegin', { handlerId: turn })]
557
+ for (let i = 0; i < 3; i++) {
558
+ events.push(ev('effectEnter', { subscriber: 'Calc#memo:a', turn }))
559
+ events.push(ev('effectExit', { subscriber: 'Calc#memo:a', dur: 1, turn }))
560
+ }
561
+ events.push(ev('turnEnd', {}))
562
+ return events
563
+ }
564
+
565
+ test('a clean run is status ok with no findings', () => {
566
+ n = 0
567
+ // One memo run in a turn → runsPerTurn 1 → not hot, nothing flagged.
568
+ const turn = 'Calc#handler:s0:click'
569
+ const events: ProfilerEvent[] = [
570
+ ev('turnBegin', { handlerId: turn }),
571
+ ev('effectEnter', { subscriber: 'Calc#memo:a', turn }),
572
+ ev('effectExit', { subscriber: 'Calc#memo:a', dur: 1, turn }),
573
+ ev('turnEnd', {}),
574
+ ]
575
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events })
576
+ expect(r.status).toBe('ok')
577
+ expect(r.findings).toHaveLength(0)
578
+ expect(r.coverage.ratio).toBe(1)
579
+ expect(r.guidance).toBeUndefined()
580
+ })
581
+
582
+ test('a hot subscriber becomes a warning finding with valid nextCommands', () => {
583
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events: hotRunEvents() })
584
+ expect(r.status).toBe('warning')
585
+ const hot = r.findings.find(f => f.kind === 'hot-subscriber')!
586
+ expect(hot.severity).toBe('warning')
587
+ expect(hot.actionable).toBe(true)
588
+ expect(hot.subscriber).toBe('Calc#memo:a')
589
+ // A memo id maps to a name `bf debug trace` accepts; graph is the fallback.
590
+ expect(hot.nextCommands).toContain('bf debug trace Calc a --json')
591
+ expect(hot.nextCommands).toContain('bf debug graph Calc --json')
592
+ })
593
+
594
+ test('an unresolved id is an actionable coverage-gap finding', () => {
595
+ n = 0
596
+ // A profiler-shaped id with no matching IR node → SR4 coverage gap.
597
+ const events: ProfilerEvent[] = [ev('effectEnter', { subscriber: 'Calc#memo:ghost' })]
598
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events })
599
+ const gap = r.findings.find(f => f.kind === 'coverage-gap')!
600
+ expect(gap.actionable).toBe(true)
601
+ expect(gap.subscriber).toBe('Calc#memo:ghost')
602
+ })
603
+
604
+ test('nextCommands target the component parsed from the id, not the root', () => {
605
+ n = 0
606
+ // A scenario-file run resolves subscribers from composed children: the id's
607
+ // component (`Child`) differs from the profiled root (`Calc`). Follow-up
608
+ // commands must target `Child`, or they point an agent at the wrong file.
609
+ const events: ProfilerEvent[] = [ev('effectEnter', { subscriber: 'Child#memo:ghost' })]
610
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events })
611
+ const gap = r.findings.find(f => f.kind === 'coverage-gap')!
612
+ expect(gap.nextCommands).toContain('bf debug trace Child ghost --json')
613
+ expect(gap.nextCommands).toContain('bf debug graph Child --json')
614
+ expect(gap.nextCommands.every(c => !c.includes('graph Calc'))).toBe(true)
615
+ })
616
+
617
+ test('coverage.ratio is clamped to 1 when the stream over-counts handlers', () => {
618
+ n = 0
619
+ // Calc exposes a single handler (handlersTotal 1), but a malformed stream
620
+ // reports two distinct turn ids — without clamping the ratio would be 2.0
621
+ // and silently pass a `--min-coverage` gate it shouldn't.
622
+ const events: ProfilerEvent[] = [
623
+ ev('effectEnter', { subscriber: 'Calc#memo:a', turn: 'Calc#handler:s0:click' }),
624
+ ev('effectEnter', { subscriber: 'Calc#memo:a', turn: 'Calc#handler:s9:click' }),
625
+ ]
626
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events })
627
+ expect(r.coverage.ratio).toBe(1)
628
+ expect(r.coverage.ratio).toBeLessThanOrEqual(1)
629
+ })
630
+
631
+ test('a zero-turn run emits guidance pointing at a story file', () => {
632
+ n = 0
633
+ // Handlers exist (the onClick) but none fired → no-interactions guidance.
634
+ const events: ProfilerEvent[] = [ev('effectEnter', { subscriber: 'Calc#memo:a' })]
635
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events })
636
+ expect(r.turns).toBe(0)
637
+ expect(r.guidance?.reason).toBe('no-interactions')
638
+ expect(r.guidance?.nextCommands[0]).toContain('--scenario <story.tsx>')
639
+ })
640
+
641
+ describe('evaluateProfileGates', () => {
642
+ test('hot gate fails when a subscriber exceeds the runs/turn budget', () => {
643
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events: hotRunEvents() })
644
+ const fail = evaluateProfileGates(r, { maxRunsPerTurn: 2 })
645
+ expect(fail.passed).toBe(false)
646
+ expect(fail.failed).toContain('hot')
647
+ const pass = evaluateProfileGates(r, { maxRunsPerTurn: 5 })
648
+ expect(pass.passed).toBe(true)
649
+ })
650
+
651
+ test('bare --fail-on hot trips on any flagged hot subscriber', () => {
652
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events: hotRunEvents() })
653
+ const g = evaluateProfileGates(r, { failOn: ['hot'] })
654
+ expect(g.passed).toBe(false)
655
+ expect(g.checks[0].threshold).toBeNull()
656
+ })
657
+
658
+ test('coverage gate compares ratio against --min-coverage', () => {
659
+ n = 0
660
+ // Handlers exist but only mount runs, no turn → ratio 0.
661
+ const events: ProfilerEvent[] = [ev('effectEnter', { subscriber: 'Calc#memo:a' })]
662
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events })
663
+ expect(r.coverage.ratio).toBe(0)
664
+ const g = evaluateProfileGates(r, { minCoverage: 0.8 })
665
+ expect(g.passed).toBe(false)
666
+ expect(g.failed).toContain('coverage')
667
+ })
668
+
669
+ test('unresolved gate counts actionable gaps against --max-unresolved', () => {
670
+ n = 0
671
+ const events: ProfilerEvent[] = [ev('effectEnter', { subscriber: 'Calc#memo:ghost' })]
672
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events })
673
+ expect(evaluateProfileGates(r, { maxUnresolved: 0 }).passed).toBe(false)
674
+ expect(evaluateProfileGates(r, { maxUnresolved: 5 }).passed).toBe(true)
675
+ })
676
+
677
+ test('no configured gate yields an empty, passing result', () => {
678
+ const r = buildProfileReport({ source: src, filePath: 'Calc.tsx', scenario: 'auto', events: hotRunEvents() })
679
+ const g = evaluateProfileGates(r, {})
680
+ expect(g.passed).toBe(true)
681
+ expect(g.checks).toHaveLength(0)
682
+ })
683
+ })
684
+ })
package/src/index.ts CHANGED
@@ -308,6 +308,7 @@ export {
308
308
  formatWastedReReruns,
309
309
  analyzeBatchAdvisor,
310
310
  formatBatchAdvisor,
311
+ evaluateProfileGates,
311
312
  } from './profiler.ts'
312
313
  export type {
313
314
  StaticBudget,
@@ -335,6 +336,14 @@ export type {
335
336
  BatchAdvisorResult,
336
337
  BatchCandidate,
337
338
  BatchSafety,
339
+ ProfileSeverity,
340
+ ProfileStatus,
341
+ AgentFinding,
342
+ ScenarioGuidance,
343
+ GateName,
344
+ GateConfig,
345
+ GateCheck,
346
+ GateResult,
338
347
  } from './profiler.ts'
339
348
 
340
349
  // Reactive profile — findings layer (#1690 dogfood: Bug A/C/D fixes, batch-candidate dedup,
package/src/profiler.ts CHANGED
@@ -1360,6 +1360,13 @@ export interface ProfileCoverage {
1360
1360
  handlersFired: number
1361
1361
  /** Handlers the IR knows about (`buildEventSummary`). */
1362
1362
  handlersTotal: number
1363
+ /**
1364
+ * `handlersFired / handlersTotal` in `[0,1]` — the fraction of known handlers
1365
+ * this run exercised, so an agent can gate on it (`--min-coverage`) without
1366
+ * dividing the two counts itself (#1841). `1` when the component has no
1367
+ * handlers (nothing to cover ⇒ trivially complete, not a gap).
1368
+ */
1369
+ ratio: number
1363
1370
  /** SR4 ids the IR could not resolve — the honest, actionable gap. */
1364
1371
  unattributed: UnattributedId[]
1365
1372
  /**
@@ -1386,6 +1393,79 @@ export interface ProfileReport {
1386
1393
  wastedReReruns: WastedReRunsResult
1387
1394
  batchAdvisor: BatchAdvisorResult
1388
1395
  coverage: ProfileCoverage
1396
+ /**
1397
+ * Normalized run status an agent can branch on without parsing prose (#1841):
1398
+ * `ok` when nothing is flagged, `warning` when any finding is severity
1399
+ * `warning` or higher — regardless of its `actionable` flag, since an
1400
+ * unresolved-but-real cost (e.g. a hot subscriber with no source loc) is still
1401
+ * worth surfacing. A failed *gate* escalates this to `error` — but gates are
1402
+ * policy applied by the CLI from flags, so the builder only ever sets
1403
+ * `ok`/`warning` here.
1404
+ */
1405
+ status: ProfileStatus
1406
+ /**
1407
+ * Flattened, normalized findings (#1841): the hot/wasted/batch/coverage tables
1408
+ * re-expressed with a single `severity` scale, an explicit `actionable` flag,
1409
+ * and `nextCommands` — the exact follow-up `bf debug …` invocations to run.
1410
+ * The structured tables above stay the source of truth; this is the agent view.
1411
+ */
1412
+ findings: AgentFinding[]
1413
+ /**
1414
+ * Coverage guidance for an under-exercised run (#1841): present only when the
1415
+ * scenario fired no or only some handlers, which usually means a story file is
1416
+ * needed (handlers live in composed children).
1417
+ */
1418
+ guidance?: ScenarioGuidance
1419
+ }
1420
+
1421
+ // -- Agent contract (#1841): normalized severity, actionable findings, guidance
1422
+
1423
+ /** Normalized finding severity an agent can branch on without parsing prose. */
1424
+ export type ProfileSeverity = 'info' | 'warning' | 'error'
1425
+
1426
+ /** Top-level run status: `ok` (clean), `warning` (findings), `error` (gate failed). */
1427
+ export type ProfileStatus = 'ok' | 'warning' | 'error'
1428
+
1429
+ /**
1430
+ * One normalized, machine-actionable finding flattened from the per-analysis
1431
+ * tables (hot subscribers / wasted re-runs / batch advisor / coverage gaps).
1432
+ * Carries the agent contract fields the issue asks for: a normalized `severity`,
1433
+ * an explicit `actionable` flag (`false` ⇒ no safe direct fix — e.g. an
1434
+ * unverified advisory), and `nextCommands` — valid, ready-to-run `bf debug …`
1435
+ * follow-ups.
1436
+ */
1437
+ export interface AgentFinding {
1438
+ kind: 'hot-subscriber' | 'wasted-re-run' | 'batch-candidate' | 'coverage-gap'
1439
+ severity: ProfileSeverity
1440
+ /**
1441
+ * Whether this finding has a concrete fix worth acting on directly. `false`
1442
+ * marks a finding an agent should *not* apply blindly — an unverified `batch()`
1443
+ * advisory (the wrap could change behavior) or a finding whose source location
1444
+ * the id index couldn't resolve. A coverage gap is `actionable: true`: the next
1445
+ * step (widen the scenario, inspect the graph) is clear even without a `loc`.
1446
+ */
1447
+ actionable: boolean
1448
+ /** The compiler subscriber/turn id this finding is about, when it has one. */
1449
+ subscriber?: string
1450
+ /** Source location, when the id resolved to an IR node. */
1451
+ loc?: { file: string; line: number }
1452
+ /** One-line human summary — the same sentence the text report would print. */
1453
+ message: string
1454
+ /** Follow-up commands to run next — valid, ready-to-run `bf debug …` lines. */
1455
+ nextCommands: string[]
1456
+ }
1457
+
1458
+ /**
1459
+ * Coverage guidance for an under-exercised run (#1841). `--scenario auto` can
1460
+ * only fire handlers the IR exposes on *this* component; for a compound/context
1461
+ * component whose handlers live in composed children it fires `0/N`, and the
1462
+ * honest next step is a story/scenario file rather than trusting a thin run.
1463
+ */
1464
+ export interface ScenarioGuidance {
1465
+ /** Why coverage was incomplete — drives the suggested next step. */
1466
+ reason: 'no-handlers' | 'no-interactions' | 'partial-coverage'
1467
+ message: string
1468
+ nextCommands: string[]
1389
1469
  }
1390
1470
 
1391
1471
  export interface ProfileReportInput {
@@ -1412,6 +1492,104 @@ export interface ProfileReportInput {
1412
1492
  wastedRatio?: number
1413
1493
  }
1414
1494
 
1495
+ /**
1496
+ * The follow-up `bf debug …` commands an agent should run to investigate a
1497
+ * subscriber finding (#1841). Every command is valid and ready to run: a
1498
+ * memo/signal id resolves to a name `bf debug trace` accepts; a DOM-binding id
1499
+ * resolves to a slotId `bf debug why-update` accepts; `bf debug graph` is always
1500
+ * applicable, so it is the universal fallback.
1501
+ *
1502
+ * Commands target the component parsed *from the id* (`<Component>#…`), not the
1503
+ * primary component — a scenario-file run resolves subscribers from composed
1504
+ * children (`extraSources`), so a child's finding must point at the child. The
1505
+ * passed `fallbackComponent` is used only for ids that don't parse (e.g. an
1506
+ * anonymous `e1`).
1507
+ */
1508
+ function nextCommandsForSubscriber(fallbackComponent: string, subscriber: string): string[] {
1509
+ const cmds: string[] = []
1510
+ const parsed = parseProfilerId(subscriber)
1511
+ const component = parsed?.component ?? fallbackComponent
1512
+ if (parsed) {
1513
+ if (parsed.kind === 'memo' || parsed.kind === 'signal') {
1514
+ cmds.push(`bf debug trace ${component} ${parsed.rest} --json`)
1515
+ } else if (parsed.kind === 'binding') {
1516
+ cmds.push(`bf debug why-update ${component} ${parsed.rest} --json`)
1517
+ }
1518
+ }
1519
+ cmds.push(`bf debug graph ${component} --json`)
1520
+ return cmds
1521
+ }
1522
+
1523
+ /**
1524
+ * Flatten the per-analysis tables into the normalized agent findings (#1841).
1525
+ * Only *flagged* rows become findings — a hot subscriber that isn't `hot`, or a
1526
+ * subscriber below the wasted threshold, is data in the tables but not something
1527
+ * the agent must act on. Coverage gaps (unresolved ids) are actionable findings;
1528
+ * the non-actionable bookkeeping ids stay in `coverage.diagnostics`.
1529
+ */
1530
+ function buildAgentFindings(
1531
+ component: string,
1532
+ hotSubscribers: HotSubscribersResult,
1533
+ wastedReReruns: WastedReRunsResult,
1534
+ batchAdvisor: BatchAdvisorResult,
1535
+ unattributed: readonly UnattributedId[],
1536
+ ): AgentFinding[] {
1537
+ const findings: AgentFinding[] = []
1538
+ for (const s of hotSubscribers.subscribers) {
1539
+ if (!s.hot) continue
1540
+ findings.push({
1541
+ kind: 'hot-subscriber',
1542
+ severity: 'warning',
1543
+ actionable: s.loc !== undefined,
1544
+ subscriber: s.subscriber,
1545
+ loc: s.loc,
1546
+ message: `${s.name ?? s.subscriber} ran ${s.runsPerTurn.toFixed(1)}×/turn — re-run pressure (split or batch).`,
1547
+ nextCommands: nextCommandsForSubscriber(component, s.subscriber),
1548
+ })
1549
+ }
1550
+ for (const s of wastedReReruns.subscribers) {
1551
+ if (!s.wasted) continue
1552
+ findings.push({
1553
+ kind: 'wasted-re-run',
1554
+ severity: 'warning',
1555
+ actionable: s.loc !== undefined,
1556
+ subscriber: s.subscriber,
1557
+ loc: s.loc,
1558
+ message: `${s.name ?? s.subscriber} produced identical output in ${Math.round(s.wastedRatio * 100)}% of runs — finer split.`,
1559
+ nextCommands: nextCommandsForSubscriber(component, s.subscriber),
1560
+ })
1561
+ }
1562
+ for (const c of batchAdvisor.candidates) {
1563
+ findings.push({
1564
+ kind: 'batch-candidate',
1565
+ // Only a *proven-safe* batch is advised as actionable warning; an
1566
+ // unverified one is surfaced as info so an agent doesn't apply a wrap that
1567
+ // could change behavior (mirrors the batch advisor's own safety gate).
1568
+ severity: c.safety === 'safe' ? 'warning' : 'info',
1569
+ actionable: c.safety === 'safe' && c.loc !== undefined,
1570
+ subscriber: c.turn,
1571
+ loc: c.loc,
1572
+ message: `${c.handler ?? c.turn} re-ran shared effects ${c.savings}× extra across ${c.writes} writes — batch() candidate (${c.safety}).`,
1573
+ // The turn id is `<Component>#handler:…` — for a scenario-file run it can be
1574
+ // a composed child, so route through the helper to target the right one.
1575
+ nextCommands: nextCommandsForSubscriber(component, c.turn),
1576
+ })
1577
+ }
1578
+ for (const u of unattributed) {
1579
+ findings.push({
1580
+ kind: 'coverage-gap',
1581
+ severity: 'warning',
1582
+ actionable: true,
1583
+ subscriber: u.id,
1584
+ message: `Unresolved subscriber id "${u.id}" — could not map to source (scope caveat).`,
1585
+ // `u.id` is shaped `<Component>#…` and may name a composed child — route
1586
+ // through the helper so the command targets that component, not the root.
1587
+ nextCommands: nextCommandsForSubscriber(component, u.id),
1588
+ })
1589
+ }
1590
+ return findings
1591
+ }
1592
+
1415
1593
  /**
1416
1594
  * Assemble a dynamic profile (SR1–SR4 + analyses, SR7) from a recorded event
1417
1595
  * stream. Pure: the DOM run that *produces* `events` lives in the driver (the
@@ -1524,6 +1702,41 @@ export function buildProfileReport(input: ProfileReportInput): ProfileReport {
1524
1702
  }
1525
1703
  }
1526
1704
 
1705
+ const findings = buildAgentFindings(primary.componentName, hotSubscribers, wastedReReruns, batchAdvisor, unattributed)
1706
+ // Status is measurement-only here: any warning/error finding ⇒ `warning`. A
1707
+ // failed gate escalates to `error`, but gates are CLI policy (flags), so the
1708
+ // builder never sets `error` itself.
1709
+ const status: ProfileStatus = findings.some(f => f.severity === 'warning' || f.severity === 'error') ? 'warning' : 'ok'
1710
+
1711
+ // Coverage ratio: 1 when there is nothing to cover (no handlers), else the
1712
+ // exercised fraction. Clamped to `[0,1]` — a malformed stream (more distinct
1713
+ // turn ids than `buildEventSummary` knows about, e.g. missing `extraSources`)
1714
+ // must not push the ratio past 1 and break a gate's assumptions. Drives
1715
+ // `--min-coverage` and the guidance below.
1716
+ const ratio = handlersTotal > 0 ? Math.min(1, handlerIds.size / handlersTotal) : 1
1717
+ let guidance: ScenarioGuidance | undefined
1718
+ if (turnSeqs.size === 0) {
1719
+ guidance =
1720
+ handlersTotal === 0
1721
+ ? {
1722
+ reason: 'no-handlers',
1723
+ message: 'No event handlers — use the static budget instead of a dynamic run.',
1724
+ nextCommands: [`bf debug profile ${primary.componentName} --json`],
1725
+ }
1726
+ : {
1727
+ reason: 'no-interactions',
1728
+ message:
1729
+ 'Handlers exist but none fired — they likely live in composed children. Drive the component with a story/scenario file.',
1730
+ nextCommands: [`bf debug profile ${primary.componentName} --scenario <story.tsx> --json`],
1731
+ }
1732
+ } else if (ratio < 1) {
1733
+ guidance = {
1734
+ reason: 'partial-coverage',
1735
+ message: `Only ${handlerIds.size}/${handlersTotal} handlers exercised — a story/scenario file can cover the rest.`,
1736
+ nextCommands: [`bf debug profile ${primary.componentName} --scenario <story.tsx> --json`],
1737
+ }
1738
+ }
1739
+
1527
1740
  return {
1528
1741
  kind: 'profile',
1529
1742
  schemaVersion: PROFILE_SCHEMA_VERSION,
@@ -1538,12 +1751,16 @@ export function buildProfileReport(input: ProfileReportInput): ProfileReport {
1538
1751
  coverage: {
1539
1752
  handlersFired: handlerIds.size,
1540
1753
  handlersTotal,
1754
+ ratio,
1541
1755
  unattributed,
1542
1756
  // Roll the (potentially hundreds of) bookkeeping ids up to a count + a
1543
1757
  // small sample so JSON consumers aren't flooded (#1849 B7). `diagnostics`
1544
1758
  // is already sorted hottest-first by `joinProfilerEvents`.
1545
1759
  diagnostics: { count: diagnostics.length, sample: diagnostics.slice(0, 3).map(d => d.id) },
1546
1760
  },
1761
+ status,
1762
+ findings,
1763
+ ...(guidance ? { guidance } : {}),
1547
1764
  }
1548
1765
  }
1549
1766
 
@@ -1579,5 +1796,116 @@ export function formatProfileReport(r: ProfileReport): string {
1579
1796
  if (c.diagnostics.count > 0) {
1580
1797
  lines.push(` · ${c.diagnostics.count} anonymous runtime id(s) (non-actionable bookkeeping)`)
1581
1798
  }
1799
+ // Agent contract footer (#1841): a normalized status and the single most
1800
+ // useful next command, so a human reading the text output sees the same
1801
+ // signal `--json` consumers branch on.
1802
+ lines.push('')
1803
+ lines.push(`status: ${r.status} (${r.findings.length} finding(s))`)
1804
+ if (r.guidance) {
1805
+ lines.push(` guidance: ${r.guidance.message}`)
1806
+ lines.push(` next: ${r.guidance.nextCommands[0]}`)
1807
+ } else if (r.findings.length > 0) {
1808
+ lines.push(` next: ${r.findings[0].nextCommands[0]}`)
1809
+ }
1582
1810
  return lines.join('\n')
1583
1811
  }
1812
+
1813
+ // -- Gates (#1841): turn a measured report into a pass/fail CI decision --------
1814
+
1815
+ /** The gate names `--fail-on` accepts. `regression` applies to `--diff` mode. */
1816
+ export type GateName = 'unresolved' | 'hot' | 'coverage' | 'regression'
1817
+
1818
+ /**
1819
+ * Gate thresholds an agent/CI supplies via flags. A gate is *active* when it is
1820
+ * named in `failOn` or its numeric threshold is set — so `--max-unresolved 0`
1821
+ * enforces the unresolved gate without also passing `--fail-on unresolved`.
1822
+ */
1823
+ export interface GateConfig {
1824
+ failOn?: readonly GateName[]
1825
+ /** `--min-coverage`: minimum `coverage.ratio` in `[0,1]`. */
1826
+ minCoverage?: number
1827
+ /** `--max-runs-per-turn`: budget for the hottest subscriber's runs/turn. */
1828
+ maxRunsPerTurn?: number
1829
+ /** `--max-unresolved`: maximum allowed unresolved (actionable) coverage gaps. */
1830
+ maxUnresolved?: number
1831
+ }
1832
+
1833
+ export interface GateCheck {
1834
+ gate: GateName
1835
+ passed: boolean
1836
+ /** The measured value the gate compared (ratio, count, or runs/turn). */
1837
+ observed: number
1838
+ /** The threshold it was compared against; `null` for a boolean gate. */
1839
+ threshold: number | null
1840
+ message: string
1841
+ }
1842
+
1843
+ export interface GateResult {
1844
+ passed: boolean
1845
+ /** Names of the gates that failed — the `gates.failed` an agent branches on. */
1846
+ failed: GateName[]
1847
+ checks: GateCheck[]
1848
+ }
1849
+
1850
+ /**
1851
+ * Evaluate the dynamic-run gates (#1841) against a measured report. Pure: maps a
1852
+ * `ProfileReport` + thresholds to a pass/fail decision the CLI turns into an
1853
+ * exit code. The `regression` gate is *not* evaluated here — it belongs to
1854
+ * `--diff` mode, which the CLI gates directly off the `BudgetDiff`.
1855
+ */
1856
+ export function evaluateProfileGates(report: ProfileReport, config: GateConfig): GateResult {
1857
+ const failOn = new Set(config.failOn ?? [])
1858
+ const checks: GateCheck[] = []
1859
+
1860
+ if (failOn.has('coverage') || config.minCoverage !== undefined) {
1861
+ const threshold = config.minCoverage ?? 1
1862
+ const observed = report.coverage.ratio
1863
+ checks.push({
1864
+ gate: 'coverage',
1865
+ passed: observed >= threshold,
1866
+ observed,
1867
+ threshold,
1868
+ message: `coverage ${(observed * 100).toFixed(0)}% ${observed >= threshold ? '≥' : '<'} required ${(threshold * 100).toFixed(0)}%`,
1869
+ })
1870
+ }
1871
+
1872
+ if (failOn.has('unresolved') || config.maxUnresolved !== undefined) {
1873
+ const threshold = config.maxUnresolved ?? 0
1874
+ const observed = report.coverage.unattributed.length
1875
+ checks.push({
1876
+ gate: 'unresolved',
1877
+ passed: observed <= threshold,
1878
+ observed,
1879
+ threshold,
1880
+ message: `${observed} unresolved id(s) ${observed <= threshold ? '≤' : '>'} allowed ${threshold}`,
1881
+ })
1882
+ }
1883
+
1884
+ if (failOn.has('hot') || config.maxRunsPerTurn !== undefined) {
1885
+ const observed = report.hotSubscribers.subscribers.reduce((m, s) => Math.max(m, s.runsPerTurn), 0)
1886
+ if (config.maxRunsPerTurn !== undefined) {
1887
+ // Numeric budget: the hottest subscriber must not exceed it.
1888
+ const threshold = config.maxRunsPerTurn
1889
+ checks.push({
1890
+ gate: 'hot',
1891
+ passed: observed <= threshold,
1892
+ observed,
1893
+ threshold,
1894
+ message: `max ${observed.toFixed(1)} runs/turn ${observed <= threshold ? '≤' : '>'} budget ${threshold}`,
1895
+ })
1896
+ } else {
1897
+ // Bare `--fail-on hot`: any subscriber the analysis flagged `hot` fails it.
1898
+ const anyHot = report.hotSubscribers.subscribers.some(s => s.hot)
1899
+ checks.push({
1900
+ gate: 'hot',
1901
+ passed: !anyHot,
1902
+ observed,
1903
+ threshold: null,
1904
+ message: anyHot ? `hot subscriber(s) present (max ${observed.toFixed(1)} runs/turn)` : 'no hot subscribers',
1905
+ })
1906
+ }
1907
+ }
1908
+
1909
+ const failed = checks.filter(c => !c.passed).map(c => c.gate)
1910
+ return { passed: failed.length === 0, failed, checks }
1911
+ }