Skip to content

Commit 1995da7

Browse files
committed
sdk
1 parent 764a0b6 commit 1995da7

8 files changed

Lines changed: 167 additions & 117 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ List only the skills this repository should actively use.
174174
- Use `.editorconfig`, project files, and checked-in docs as the durable source of tooling truth.
175175
- Keep names, namespaces, and future .NET projects under the `ManagedCode.Tps` prefix unless a documented exception is approved.
176176
- Every TPS runtime library must publish a clear list of spec constants for keywords, tags, emotions, metadata keys, and other validation-critical terms.
177+
- Do not introduce magic string literals or repeated catalog literals for TPS spec terms, statuses, diagnostic codes, emotion names, palette keys, or similar runtime-contract data; define and reuse named constants.
177178
- Every TPS runtime library must include TPS format validation that reports actionable diagnostics for invalid structure, unknown tags, malformed attributes, and other authoring errors.
178179
- Keep each runtime in its own language folder under `SDK/`, and keep SDK design/testing/ADR documentation under `SDK/docs/`.
179180
- Design CI so the active runtime set is extensible beyond JavaScript, TypeScript, and C#, with future language additions enabled by configuration instead of ad hoc workflow rewrites.

SDK/dotnet/src/ManagedCode.Tps/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ For this .NET project:
6666
- Keep the `ManagedCode.Tps` namespace prefix intact.
6767
- Do not place test helpers or test-only code in this project.
6868
- Prefer small, composable types over large utility buckets.
69+
- Do not add new TPS catalog literals inline when the value is part of the public runtime contract; expose and reuse named constants instead.
6970

7071
## Exception Record
7172

SDK/dotnet/src/ManagedCode.Tps/Internal/TpsContentCompiler.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ private static ActiveInlineState ResolveActiveState(List<InlineScope> scopes, In
500500
string? inlineEmotion = null;
501501
string? volumeLevel = null;
502502
string? deliveryMode = null;
503-
string? articulationStyle = (string?)null;
503+
var articulationStyle = default(string);
504504
int? energyLevel = null;
505505
int? melodyLevel = null;
506506
string? phoneticGuide = null;
@@ -541,8 +541,15 @@ private static ActiveInlineState ResolveActiveState(List<InlineScope> scopes, In
541541
volumeLevel = scope.VolumeLevel ?? volumeLevel;
542542
deliveryMode = scope.DeliveryMode ?? deliveryMode;
543543
articulationStyle = scope.ArticulationStyle ?? articulationStyle;
544-
if (scope.EnergyLevel is int scopeEnergy) energyLevel = scopeEnergy;
545-
if (scope.MelodyLevel is int scopeMelody) melodyLevel = scopeMelody;
544+
if (scope.EnergyLevel is int scopeEnergy)
545+
{
546+
energyLevel = scopeEnergy;
547+
}
548+
549+
if (scope.MelodyLevel is int scopeMelody)
550+
{
551+
melodyLevel = scopeMelody;
552+
}
546553
phoneticGuide = scope.PhoneticGuide ?? phoneticGuide;
547554
pronunciationGuide = scope.PronunciationGuide ?? pronunciationGuide;
548555
stressGuide = scope.StressGuide ?? stressGuide;
@@ -682,8 +689,15 @@ public void Apply(ActiveInlineState state, char character)
682689
VolumeLevel = state.VolumeLevel ?? VolumeLevel;
683690
DeliveryMode = state.DeliveryMode ?? DeliveryMode;
684691
ArticulationStyle = state.ArticulationStyle ?? ArticulationStyle;
685-
if (state.EnergyLevel is int stateEnergy) EnergyLevel = stateEnergy;
686-
if (state.MelodyLevel is int stateMelody) MelodyLevel = stateMelody;
692+
if (state.EnergyLevel is int stateEnergy)
693+
{
694+
EnergyLevel = stateEnergy;
695+
}
696+
697+
if (state.MelodyLevel is int stateMelody)
698+
{
699+
MelodyLevel = stateMelody;
700+
}
687701
PhoneticGuide = state.PhoneticGuide ?? PhoneticGuide;
688702
PronunciationGuide = state.PronunciationGuide ?? PronunciationGuide;
689703
StressGuide = state.StressGuide ?? StressGuide;

SDK/dotnet/src/ManagedCode.Tps/Internal/TpsParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using System.Globalization;
21
using System.Collections.ObjectModel;
2+
using System.Globalization;
33
using System.Text.RegularExpressions;
44
using ManagedCode.Tps.Models;
55

SDK/dotnet/src/ManagedCode.Tps/TpsPlaybackSession.cs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -607,28 +607,12 @@ private async Task RunPlaybackLoopAsync(CancellationTokenSource cancellationToke
607607
}
608608
}
609609

610-
private int ReadLiveElapsed()
611-
{
612-
lock (_syncRoot)
613-
{
614-
return ReadLiveElapsedLocked();
615-
}
616-
}
617-
618610
private int ReadLiveElapsedLocked()
619611
{
620612
var deltaMs = Math.Max(0d, _timeProvider.GetElapsedTime(_playbackStartedAtTimestamp).TotalMilliseconds);
621613
return _playbackOffsetMs + (int)Math.Max(0d, Math.Round(deltaMs * PlaybackRate, MidpointRounding.AwayFromZero));
622614
}
623615

624-
private Transition UpdatePosition(int elapsedMs, TpsPlaybackStatus requestedStatus)
625-
{
626-
lock (_syncRoot)
627-
{
628-
return UpdatePositionLocked(elapsedMs, requestedStatus);
629-
}
630-
}
631-
632616
private Transition UpdatePositionLocked(int elapsedMs, TpsPlaybackStatus requestedStatus)
633617
{
634618
var previousState = CurrentState;
@@ -662,25 +646,6 @@ private Transition UpdatePositionLocked(int elapsedMs, TpsPlaybackStatus request
662646
nextStatus == TpsPlaybackStatus.Completed && previousStatus != TpsPlaybackStatus.Completed);
663647
}
664648

665-
private Transition UpdateStatusLocked(TpsPlaybackStatus nextStatus)
666-
{
667-
var previousStatus = Status;
668-
Status = nextStatus;
669-
return new Transition(
670-
CurrentState,
671-
CurrentState,
672-
nextStatus,
673-
previousStatus,
674-
CreateSnapshotLocked(),
675-
StateChangedRaised: false,
676-
WordChangedRaised: false,
677-
PhraseChangedRaised: false,
678-
BlockChangedRaised: false,
679-
SegmentChangedRaised: false,
680-
StatusChangedRaised: previousStatus != nextStatus,
681-
CompletedRaised: false);
682-
}
683-
684649
private void Publish(Transition transition)
685650
{
686651
if (transition.StatusChangedRaised)

SDK/dotnet/src/ManagedCode.Tps/TpsSpec.cs

Lines changed: 110 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,77 @@ public static class TpsSpec
1414
public const string SpeakerPrefix = "Speaker:";
1515
public const string WpmSuffix = "WPM";
1616

17+
public static class EmotionNames
18+
{
19+
public const string Neutral = DefaultEmotion;
20+
public const string Warm = "warm";
21+
public const string Professional = "professional";
22+
public const string Focused = "focused";
23+
public const string Concerned = "concerned";
24+
public const string Urgent = "urgent";
25+
public const string Motivational = "motivational";
26+
public const string Excited = "excited";
27+
public const string Happy = "happy";
28+
public const string Sad = "sad";
29+
public const string Calm = "calm";
30+
public const string Energetic = "energetic";
31+
}
32+
33+
public static class EditPointPriorityNames
34+
{
35+
public const string High = "high";
36+
public const string Medium = "medium";
37+
public const string Low = "low";
38+
}
39+
40+
public static class HeadCueCodes
41+
{
42+
public const string H0 = "H0";
43+
public const string H1 = "H1";
44+
public const string H4 = "H4";
45+
public const string H5 = "H5";
46+
public const string H6 = "H6";
47+
public const string H7 = "H7";
48+
public const string H8 = "H8";
49+
public const string H9 = "H9";
50+
}
51+
52+
public static class PaletteHex
53+
{
54+
public const string AccentBlue = "#2563EB";
55+
public const string TextSlate900 = "#0F172A";
56+
public const string BackgroundBlue400 = "#60A5FA";
57+
public const string AccentOrange600 = "#EA580C";
58+
public const string TextStone900 = "#1C1917";
59+
public const string BackgroundOrange300 = "#FDBA74";
60+
public const string AccentBlue700 = "#1D4ED8";
61+
public const string BackgroundBlue300 = "#93C5FD";
62+
public const string AccentGreen700 = "#15803D";
63+
public const string TextGreen950 = "#052E16";
64+
public const string BackgroundGreen300 = "#86EFAC";
65+
public const string AccentRed700 = "#B91C1C";
66+
public const string TextRose950 = "#1F1111";
67+
public const string BackgroundRed300 = "#FCA5A5";
68+
public const string AccentRed600 = "#DC2626";
69+
public const string TextWhiteRose = "#FFF7F7";
70+
public const string AccentViolet600 = "#7C3AED";
71+
public const string TextWhite = "#FFFFFF";
72+
public const string BackgroundViolet300 = "#C4B5FD";
73+
public const string AccentPink600 = "#DB2777";
74+
public const string TextWhitePink = "#FFF7FB";
75+
public const string BackgroundPink300 = "#F9A8D4";
76+
public const string AccentAmber600 = "#D97706";
77+
public const string BackgroundAmber300 = "#FCD34D";
78+
public const string AccentIndigo600 = "#4F46E5";
79+
public const string TextIndigo50 = "#EEF2FF";
80+
public const string BackgroundIndigo300 = "#A5B4FC";
81+
public const string AccentTeal700 = "#0F766E";
82+
public const string TextTeal50 = "#F0FDFA";
83+
public const string BackgroundTeal200 = "#99F6E4";
84+
public const string AccentOrange700 = "#C2410C";
85+
public const string TextOrange50 = "#FFF7ED";
86+
}
87+
1788
public static class FrontMatterKeys
1889
{
1990
public const string Author = "author";
@@ -115,18 +186,18 @@ public static class DiagnosticCodes
115186

116187
public static IReadOnlyList<string> Emotions { get; } =
117188
[
118-
"neutral",
119-
"warm",
120-
"professional",
121-
"focused",
122-
"concerned",
123-
"urgent",
124-
"motivational",
125-
"excited",
126-
"happy",
127-
"sad",
128-
"calm",
129-
"energetic"
189+
EmotionNames.Neutral,
190+
EmotionNames.Warm,
191+
EmotionNames.Professional,
192+
EmotionNames.Focused,
193+
EmotionNames.Concerned,
194+
EmotionNames.Urgent,
195+
EmotionNames.Motivational,
196+
EmotionNames.Excited,
197+
EmotionNames.Happy,
198+
EmotionNames.Sad,
199+
EmotionNames.Calm,
200+
EmotionNames.Energetic
130201
];
131202

132203
public static IReadOnlyList<string> DeliveryModes { get; } =
@@ -155,9 +226,9 @@ public static class DiagnosticCodes
155226

156227
public static IReadOnlyList<string> EditPointPriorities { get; } =
157228
[
158-
"high",
159-
"medium",
160-
"low"
229+
EditPointPriorityNames.High,
230+
EditPointPriorityNames.Medium,
231+
EditPointPriorityNames.Low
161232
];
162233

163234
public static IReadOnlyList<string> ArticulationStyles { get; } = [Tags.Legato, Tags.Staccato];
@@ -250,35 +321,35 @@ public static class ArchetypeVolumeExpectations
250321
public static IReadOnlyDictionary<string, EmotionPalette> EmotionPalettes { get; } =
251322
new Dictionary<string, EmotionPalette>(StringComparer.OrdinalIgnoreCase)
252323
{
253-
[DefaultEmotion] = new("#2563EB", "#0F172A", "#60A5FA"),
254-
["warm"] = new("#EA580C", "#1C1917", "#FDBA74"),
255-
["professional"] = new("#1D4ED8", "#0F172A", "#93C5FD"),
256-
["focused"] = new("#15803D", "#052E16", "#86EFAC"),
257-
["concerned"] = new("#B91C1C", "#1F1111", "#FCA5A5"),
258-
["urgent"] = new("#DC2626", "#FFF7F7", "#FCA5A5"),
259-
["motivational"] = new("#7C3AED", "#FFFFFF", "#C4B5FD"),
260-
["excited"] = new("#DB2777", "#FFF7FB", "#F9A8D4"),
261-
["happy"] = new("#D97706", "#1C1917", "#FCD34D"),
262-
["sad"] = new("#4F46E5", "#EEF2FF", "#A5B4FC"),
263-
["calm"] = new("#0F766E", "#F0FDFA", "#99F6E4"),
264-
["energetic"] = new("#C2410C", "#FFF7ED", "#FDBA74")
324+
[EmotionNames.Neutral] = new(PaletteHex.AccentBlue, PaletteHex.TextSlate900, PaletteHex.BackgroundBlue400),
325+
[EmotionNames.Warm] = new(PaletteHex.AccentOrange600, PaletteHex.TextStone900, PaletteHex.BackgroundOrange300),
326+
[EmotionNames.Professional] = new(PaletteHex.AccentBlue700, PaletteHex.TextSlate900, PaletteHex.BackgroundBlue300),
327+
[EmotionNames.Focused] = new(PaletteHex.AccentGreen700, PaletteHex.TextGreen950, PaletteHex.BackgroundGreen300),
328+
[EmotionNames.Concerned] = new(PaletteHex.AccentRed700, PaletteHex.TextRose950, PaletteHex.BackgroundRed300),
329+
[EmotionNames.Urgent] = new(PaletteHex.AccentRed600, PaletteHex.TextWhiteRose, PaletteHex.BackgroundRed300),
330+
[EmotionNames.Motivational] = new(PaletteHex.AccentViolet600, PaletteHex.TextWhite, PaletteHex.BackgroundViolet300),
331+
[EmotionNames.Excited] = new(PaletteHex.AccentPink600, PaletteHex.TextWhitePink, PaletteHex.BackgroundPink300),
332+
[EmotionNames.Happy] = new(PaletteHex.AccentAmber600, PaletteHex.TextStone900, PaletteHex.BackgroundAmber300),
333+
[EmotionNames.Sad] = new(PaletteHex.AccentIndigo600, PaletteHex.TextIndigo50, PaletteHex.BackgroundIndigo300),
334+
[EmotionNames.Calm] = new(PaletteHex.AccentTeal700, PaletteHex.TextTeal50, PaletteHex.BackgroundTeal200),
335+
[EmotionNames.Energetic] = new(PaletteHex.AccentOrange700, PaletteHex.TextOrange50, PaletteHex.BackgroundOrange300)
265336
};
266337

267338
public static IReadOnlyDictionary<string, string> EmotionHeadCues { get; } =
268339
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
269340
{
270-
[DefaultEmotion] = "H0",
271-
["calm"] = "H0",
272-
["professional"] = "H9",
273-
["focused"] = "H5",
274-
["motivational"] = "H9",
275-
["urgent"] = "H4",
276-
["concerned"] = "H1",
277-
["sad"] = "H1",
278-
["warm"] = "H7",
279-
["happy"] = "H6",
280-
["excited"] = "H6",
281-
["energetic"] = "H8"
341+
[EmotionNames.Neutral] = HeadCueCodes.H0,
342+
[EmotionNames.Calm] = HeadCueCodes.H0,
343+
[EmotionNames.Professional] = HeadCueCodes.H9,
344+
[EmotionNames.Focused] = HeadCueCodes.H5,
345+
[EmotionNames.Motivational] = HeadCueCodes.H9,
346+
[EmotionNames.Urgent] = HeadCueCodes.H4,
347+
[EmotionNames.Concerned] = HeadCueCodes.H1,
348+
[EmotionNames.Sad] = HeadCueCodes.H1,
349+
[EmotionNames.Warm] = HeadCueCodes.H7,
350+
[EmotionNames.Happy] = HeadCueCodes.H6,
351+
[EmotionNames.Excited] = HeadCueCodes.H6,
352+
[EmotionNames.Energetic] = HeadCueCodes.H8
282353
};
283354
}
284355

0 commit comments

Comments
 (0)