@trazum/cli 1.33.0 → 1.35.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/src/markdown.ts CHANGED
@@ -733,6 +733,20 @@ export interface ProfileMarkdownInput {
733
733
  * copy; this is a rendering and must not decide anything a gate decides.
734
734
  */
735
735
  gates?: { failed: boolean; lines: string[] };
736
+ /**
737
+ * `--markdown-summary`: the short form, for a pull-request body or a weekly
738
+ * note rather than a full report.
739
+ *
740
+ * The person who owns the budget usually does not run the CLI, and handing
741
+ * them the whole report is handing them a document to skim — where the one
742
+ * figure that changed is as easy to miss as it was in the terminal. The
743
+ * summary states what changed, the single lever worth the most, and stops.
744
+ *
745
+ * It is a *view*, never a different set of figures: every number in it is
746
+ * taken from the same report the full rendering uses, so a reader who opens
747
+ * both cannot find them disagreeing.
748
+ */
749
+ summary?: boolean;
736
750
  /**
737
751
  * The `--since`/`--until` values as the user typed them, when a window was
738
752
  * applied. Passed through rather than re-derived from `timeWindow`'s epoch
@@ -793,7 +807,7 @@ export interface ProfileMarkdownInput {
793
807
  * reading CI instead of machines.
794
808
  */
795
809
  export function renderProfileMarkdown(input: ProfileMarkdownInput): string {
796
- const { report, levers, cache, t, window, stalePricing, against, whatIf, pressure = [], gates } = input;
810
+ const { report, levers, cache, t, window, stalePricing, against, whatIf, pressure = [], gates, summary = false } = input;
797
811
  const n = (value: number): string => value.toLocaleString(t.numberLocale);
798
812
  const pct = (share: number): string => `${(share * 100).toFixed(1)}%`;
799
813
  const shares = sharesOf(report.total);
@@ -812,6 +826,85 @@ export function renderProfileMarkdown(input: ProfileMarkdownInput): string {
812
826
  * surface further out. A failure is quoted so it survives being skimmed; a
813
827
  * pass is stated plainly and does not shout.
814
828
  */
829
+ /**
830
+ * The summary: what changed, the biggest lever, and nothing else.
831
+ *
832
+ * Returned before the full rendering rather than filtered out of it, so a
833
+ * section added later cannot leak into the short form by forgetting to opt
834
+ * out. Every figure here comes from the same report the long form uses.
835
+ */
836
+ if (summary) {
837
+ const short: string[] = [];
838
+ short.push(`### ${t.profile.heading()}`);
839
+ short.push('');
840
+ if (gates !== undefined && gates.lines.length > 0) {
841
+ const [verdict] = gates.lines;
842
+ short.push(gates.failed ? `> ❌ **${mdText(verdict!)}**` : `_${mdText(verdict!)}_`);
843
+ short.push('');
844
+ }
845
+ short.push(`**${mdText(t.profile.spent(t.profile.calls(report.total.calls), formatUsd(report.total.totalUsd)))}**`);
846
+ short.push('');
847
+ // What changed, when there is a previous log to change from. Without one
848
+ // the summary states the bill and says so, rather than implying stability
849
+ // nobody measured.
850
+ if (against !== undefined) {
851
+ const delta = report.total.totalUsd - against.previousTotalUsd;
852
+ const growthPct =
853
+ against.previousTotalUsd > 0
854
+ ? `${delta >= 0 ? '+' : ''}${((delta / against.previousTotalUsd) * 100).toFixed(1)}%`
855
+ : '—';
856
+ short.push(
857
+ mdText(
858
+ t.profile.againstTotals(
859
+ formatUsd(against.previousTotalUsd),
860
+ formatUsd(report.total.totalUsd),
861
+ formatSignedUsd(delta),
862
+ growthPct,
863
+ t.profile.calls(against.previousCalls),
864
+ t.profile.calls(report.total.calls),
865
+ ),
866
+ ),
867
+ );
868
+ short.push('');
869
+ // The one driver that moved most — not five, because a summary that
870
+ // lists everything is the report again with a shorter heading.
871
+ const [driver] = against.labelDrivers;
872
+ if (driver !== undefined) {
873
+ const shown = driver.key === UNLABELLED ? t.profile.unlabelled() : driver.key;
874
+ short.push(
875
+ `- ${mdText(
876
+ driver.was === null
877
+ ? t.profile.againstDriverNew(formatSignedUsd(driver.delta), shown)
878
+ : driver.now === null
879
+ ? t.profile.againstDriverGone(formatSignedUsd(driver.delta), shown)
880
+ : t.profile.againstDriver(formatSignedUsd(driver.delta), shown, formatUsd(driver.was), formatUsd(driver.now)),
881
+ )}`,
882
+ );
883
+ short.push('');
884
+ }
885
+ } else {
886
+ short.push(`_${mdText(t.profile.summaryNoComparison())}_`);
887
+ short.push('');
888
+ }
889
+ // The single lever worth the most, with the hedge every lever carries.
890
+ const [lever] = levers.slices;
891
+ if (lever !== undefined) {
892
+ short.push(
893
+ `- ${mdText(
894
+ t.profile.leverSlice(
895
+ showLabel(lever.label),
896
+ lever.modelName,
897
+ formatUsd(lever.combinedUsd),
898
+ pct(lever.shareOfBill),
899
+ ),
900
+ )}`,
901
+ );
902
+ short.push('');
903
+ }
904
+ short.push(`_${mdText(t.profile.summaryFooter())}_`);
905
+ return short.join('\n');
906
+ }
907
+
815
908
  if (gates !== undefined && gates.lines.length > 0) {
816
909
  // One mark, on the verdict. The lines under it explain that verdict and
817
910
  // are not themselves failures — marking each would turn one red build