diff --git a/IdleSpectator/AgentHarness.cs b/IdleSpectator/AgentHarness.cs
index 79bacd9..051ff8a 100644
--- a/IdleSpectator/AgentHarness.cs
+++ b/IdleSpectator/AgentHarness.cs
@@ -3092,23 +3092,6 @@ public static class AgentHarness
break;
}
- case "saga_hover_panel_dwell":
- {
- LifeSagaViewController.HarnessSimulatePanelDwell();
- bool ok = LifeSagaViewController.IsHoverPreview;
- if (ok)
- {
- _cmdOk++;
- }
- else
- {
- _cmdFail++;
- }
-
- Emit(cmd, ok, detail: $"hoverId={LifeSagaViewController.HoverPreviewId}");
- break;
- }
-
case "saga_hover_tick_away":
{
LifeSagaViewController.HarnessTickExitAwayFromChrome();
@@ -3142,25 +3125,6 @@ public static class AgentHarness
break;
}
- case "saga_open_lore":
- {
- LifeSagaViewController.SelectTab(LifeSagaViewController.Tab.Saga);
- WatchCaption.RequestRelayout();
- LifeSagaPanel.HarnessOpenLore();
- bool ok = Chronicle.HudVisible;
- if (ok)
- {
- _cmdOk++;
- }
- else
- {
- _cmdFail++;
- }
-
- Emit(cmd, ok, detail: $"lore={ok} bound={LifeSagaPanel.BoundUnitId}");
- break;
- }
-
case "saga_select_tab":
{
string raw = (cmd.value ?? "dossier").Trim().ToLowerInvariant();
@@ -8517,9 +8481,10 @@ public static class AgentHarness
int rows = LifeSagaRail.LastHoverRowCount;
float height = LifeSagaRail.LastHoverHeight;
pass = LifeSagaViewController.EffectiveTab == LifeSagaViewController.Tab.Saga
- && height >= 100f
- && height <= 200f;
- detail = $"snapshot rows={rows} height={height:0.0} tab={LifeSagaViewController.EffectiveTab} compact={pass}";
+ && height >= LifeSagaPanel.BodyHeightMin - 0.5f
+ && height <= LifeSagaPanel.BodyHeightMax + 0.5f;
+ detail =
+ $"snapshot rows={rows} height={height:0.0} tab={LifeSagaViewController.EffectiveTab} min={LifeSagaPanel.BodyHeightMin} max={LifeSagaPanel.BodyHeightMax}";
break;
}
case "saga_tab_selected":
@@ -8567,14 +8532,25 @@ public static class AgentHarness
detail = $"boundId={model?.UnitId ?? 0} name='{model?.Name}' lens={model?.PrimaryLens}";
break;
}
- case "saga_panel_evidence":
+ case "saga_dossier_chrome_restored":
+ {
+ bool onDossier = LifeSagaViewController.EffectiveTab == LifeSagaViewController.Tab.Dossier
+ && !LifeSagaViewController.IsHoverPreview;
+ bool sagaHidden = !LifeSagaPanel.Visible;
+ bool chrome = WatchCaption.HarnessDossierChromeRestored();
+ pass = onDossier && sagaHidden && chrome;
+ detail =
+ $"onDossier={onDossier} sagaHidden={sagaHidden} chrome={chrome} reason='{WatchCaption.LastDetail}'";
+ break;
+ }
+ case "saga_panel_lens":
{
LifeSagaViewModel model = LifeSagaViewController.BuildEffectivePresentation();
bool want = ParseBool(cmd.value, defaultValue: true);
- bool have = model != null && !string.IsNullOrEmpty(model.EvidenceLine);
+ bool have = model != null && !string.IsNullOrEmpty(model.LensEyebrow);
pass = have == want;
detail =
- $"evidence='{model?.EvidenceTitle}:{model?.EvidenceLine}' want={want} lens={model?.PrimaryLens}";
+ $"lensEyebrow='{model?.LensEyebrow}' want={want} primary={model?.PrimaryLens}";
break;
}
case "saga_panel_empty":
diff --git a/IdleSpectator/HarnessScenarios.cs b/IdleSpectator/HarnessScenarios.cs
index 33176a9..6a4e747 100644
--- a/IdleSpectator/HarnessScenarios.cs
+++ b/IdleSpectator/HarnessScenarios.cs
@@ -3044,16 +3044,14 @@ internal static class HarnessScenarios
Step("sad19", "assert", expect: "saga_tab_effective", value: "saga"),
Step("sad20", "assert", expect: "saga_hover_preview", value: "true"),
Step("sad21", "assert", expect: "saga_read_pause", value: "true"),
- // Panel dwell clears the exit timer; leaving chrome must re-arm and restore Dossier.
- Step("sad21b", "saga_hover_panel_dwell"),
- Step("sad21c", "saga_hover_tick_away"),
- Step("sad21d", "wait", wait: 0.1f),
- Step("sad21e", "saga_hover_tick_away"),
- Step("sad21f", "wait", wait: 0.4f),
- Step("sad21g", "saga_hover_tick_away"),
+ // Leaving the glyph restores Dossier immediately (no panel-dwell keep-alive).
+ Step("sad21b", "saga_hide_hover"),
+ Step("sad21d", "saga_hover_tick_away"),
Step("sad21h", "assert", expect: "saga_hover_preview", value: "false"),
Step("sad21i", "assert", expect: "saga_tab_effective", value: "dossier"),
Step("sad21j", "assert", expect: "saga_read_pause", value: "false"),
+ // Dossier chrome must restore immediately (not wait for a tip ownership change).
+ Step("sad21j2", "assert", expect: "saga_dossier_chrome_restored"),
Step("sad21k", "saga_show_hover_first"),
Step("sad21l", "assert", expect: "saga_hover_preview", value: "true"),
// Tab click during preview cancels preview and applies the selected tab.
@@ -3062,14 +3060,15 @@ internal static class HarnessScenarios
Step("sad21o", "assert", expect: "saga_tab_effective", value: "dossier"),
Step("sad22", "saga_show_hover_first"),
Step("sad22b", "saga_hide_hover"),
- Step("sad23", "wait", wait: 0.4f),
Step("sad23b", "saga_hover_tick_away"),
Step("sad24", "assert", expect: "saga_hover_preview", value: "false"),
Step("sad25", "assert", expect: "saga_tab_effective", value: "dossier"),
Step("sad26", "assert", expect: "saga_read_pause", value: "false"),
Step("sad27", "assert", expect: "saga_overview_tip_not", value: "Fighting |Why |Now |Notable "),
Step("sad28", "saga_select_tab", value: "saga"),
- Step("sad29", "assert", expect: "saga_panel_evidence", value: "true"),
+ Step("sad29", "assert", expect: "saga_panel_lens", value: "true"),
+ Step("sad29b", "assert", expect: "saga_overview_tip_not",
+ value: "Evidence|kills ·|remembered clashes|Open Lore"),
// Non-MC watch with no pin → empty pick state; rail click pins subject.
Step("sad30", "interest_saga_clear"),
Step("sad31", "spawn", asset: "human", count: 2),
@@ -3085,12 +3084,6 @@ internal static class HarnessScenarios
Step("sad41", "assert", expect: "saga_panel_empty", value: "false"),
Step("sad42", "assert", expect: "saga_panel_bound"),
Step("sad43", "screenshot", value: "saga-rail-top"),
- // Open Lore from Saga and restore Saga on close.
- Step("sad44", "saga_open_lore"),
- Step("sad45", "assert", expect: "chronicle_visible", value: "true"),
- Step("sad46", "lore_close"),
- Step("sad47", "assert", expect: "saga_tab_effective", value: "saga"),
- Step("sad48", "assert", expect: "saga_panel_bound"),
Step("sad90", "fast_timing", value: "false"),
Step("sad99", "snapshot"),
};
@@ -3155,7 +3148,7 @@ internal static class HarnessScenarios
Step("shp17", "assert", expect: "tip_contains", value: "PauseHold"),
Step("shp18", "assert", expect: "tip_not_contains", value: "ShouldNotCut"),
Step("shp19", "saga_hide_hover"),
- Step("shp20", "wait", wait: 0.35f),
+ Step("shp20", "saga_hover_tick_away"),
Step("shp21", "assert", expect: "saga_read_pause", value: "false"),
Step("shp90", "fast_timing", value: "false"),
Step("shp99", "snapshot"),
diff --git a/IdleSpectator/Story/LifeSagaOverview.cs b/IdleSpectator/Story/LifeSagaOverview.cs
index 1d65ef5..132fdea 100644
--- a/IdleSpectator/Story/LifeSagaOverview.cs
+++ b/IdleSpectator/Story/LifeSagaOverview.cs
@@ -44,12 +44,12 @@ public static class LifeSagaOverview
});
}
- if (!string.IsNullOrEmpty(model.EvidenceLine))
+ if (!string.IsNullOrEmpty(model.LensEyebrow))
{
snapshot.Rows.Add(new LifeSagaSnapshotRow
{
Kind = LifeSagaSnapshotRowKind.Current,
- Text = model.EvidenceTitle + ": " + model.EvidenceLine
+ Text = model.LensEyebrow
});
}
diff --git a/IdleSpectator/Story/LifeSagaPanel.cs b/IdleSpectator/Story/LifeSagaPanel.cs
index cae53f9..c3897e3 100644
--- a/IdleSpectator/Story/LifeSagaPanel.cs
+++ b/IdleSpectator/Story/LifeSagaPanel.cs
@@ -1,13 +1,13 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
-using UnityEngine.Events;
using UnityEngine.UI;
namespace IdleSpectator;
///
-/// Saga body matching Design A (cast + stakes): identity, stake, cast, evidence, legacy, Open Lore.
+/// Saga story card: identity + stake beside the portrait, Cast and Legacy full-width under it.
+/// No Evidence stats dump and no Open Lore button (L still opens Lore).
/// Width is fixed to the tabbed chrome so right-anchored hover cannot slide the rail.
/// Height sizes to content (capped) so lines wrap fully instead of ellipsis.
///
@@ -28,29 +28,26 @@ public static class LifeSagaPanel
private const float ColGap = 6f;
private const float CastFace = 16f;
private const float CastSlotW = 54f;
- private const float LoreH = 11f;
private const float SecLabelH = 10f;
private const float LineH = 10f;
+ private const int EyebrowFont = 7;
private const int NameFont = 9;
private const int TitleFont = 7;
private const int StakeFont = 8;
private const int BodyFont = 7;
private const int MaxCast = 4;
private const int MaxLegacy = 5;
- private const int BuildVersion = 7;
+ private const int BuildVersion = 8;
private static GameObject _root;
private static RectTransform _rootRt;
+ private static Text _eyebrowText;
private static Text _nameText;
private static Text _titleText;
private static Text _stakeText;
private static Text _castHead;
- private static Text _evidenceHead;
- private static Text _evidenceText;
private static Text _legacyHead;
private static Text _legacyText;
- private static Button _loreBtn;
- private static Text _loreBtnLabel;
private static readonly CastSlot[] CastSlots = new CastSlot[MaxCast];
private static long _boundId;
private static string _speciesId = "";
@@ -93,16 +90,13 @@ public static class LifeSagaPanel
Object.Destroy(_root);
_root = null;
_rootRt = null;
+ _eyebrowText = null;
_nameText = null;
_titleText = null;
_stakeText = null;
_castHead = null;
- _evidenceHead = null;
- _evidenceText = null;
_legacyHead = null;
_legacyText = null;
- _loreBtn = null;
- _loreBtnLabel = null;
}
_root = new GameObject("LifeSagaPanel", typeof(RectTransform));
@@ -113,6 +107,7 @@ public static class LifeSagaPanel
_rootRt.anchorMax = new Vector2(0f, 1f);
_rootRt.sizeDelta = new Vector2(BodyWidthFixed, BodyHeightMin);
+ _eyebrowText = MakeLabel(_root.transform, "SagaEyebrow", EyebrowFont, HudTheme.Muted, FontStyle.Normal);
_nameText = MakeLabel(_root.transform, "SagaName", NameFont, HudTheme.ValueOrange, FontStyle.Bold);
_titleText = MakeLabel(_root.transform, "SagaTitle", TitleFont, HudTheme.Muted, FontStyle.Normal);
_stakeText = MakeLabel(_root.transform, "StakeBody", StakeFont, HudTheme.ValueOrange, FontStyle.Bold);
@@ -120,11 +115,6 @@ public static class LifeSagaPanel
_stakeText.verticalOverflow = VerticalWrapMode.Overflow;
_castHead = MakeLabel(_root.transform, "CastHead", BodyFont, HudTheme.Muted, FontStyle.Bold);
_castHead.text = "Cast";
- _evidenceHead = MakeLabel(_root.transform, "EvidenceHead", BodyFont, HudTheme.Muted, FontStyle.Bold);
- _evidenceHead.text = "Evidence";
- _evidenceText = MakeLabel(_root.transform, "EvidenceBody", BodyFont, HudTheme.Body, FontStyle.Normal);
- _evidenceText.horizontalOverflow = HorizontalWrapMode.Wrap;
- _evidenceText.verticalOverflow = VerticalWrapMode.Overflow;
_legacyHead = MakeLabel(_root.transform, "LegacyHead", BodyFont, HudTheme.Muted, FontStyle.Bold);
_legacyHead.text = "Legacy";
_legacyText = MakeLabel(_root.transform, "LegacyBody", BodyFont, HudTheme.Body, FontStyle.Normal);
@@ -136,23 +126,6 @@ public static class LifeSagaPanel
CastSlots[i] = BuildCast(i);
}
- GameObject loreGo = new GameObject("SagaLoreBtn", typeof(RectTransform), typeof(Image), typeof(Button));
- loreGo.transform.SetParent(_root.transform, false);
- Image loreBg = loreGo.GetComponent();
- loreBg.color = new Color(0f, 0f, 0f, 0f);
- loreBg.raycastTarget = true;
- _loreBtn = loreGo.GetComponent