Implement Phase S1-D skill authoring examples and validation harness
This commit is contained in:
parent
956fb4f2ea
commit
9d0a41ab07
15 changed files with 1304 additions and 13 deletions
|
|
@ -3997,6 +3997,27 @@ FHyperTwistSkillAuditLedgerState UHyperTwistContractLibrary::MakeSampleSkillAudi
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistSkillAuthoringHarnessState UHyperTwistContractLibrary::MakeSampleSkillAuthoringHarnessState()
|
||||
{
|
||||
const FHyperTwistSkillRegistryState RegistryState = MakeSampleSkillRegistryState();
|
||||
const FHyperTwistSkillControlState ControlState =
|
||||
UHyperTwistSkillCoreLibrary::DeriveSkillControlState(
|
||||
RegistryState,
|
||||
HyperTwistContractLibraryInternal::MakeSampleSkillAuditControlProfile()
|
||||
);
|
||||
const FHyperTwistSkillAuditLedgerState AuditLedgerState =
|
||||
UHyperTwistSkillCoreLibrary::DeriveSkillAuditLedgerState(
|
||||
RegistryState,
|
||||
ControlState
|
||||
);
|
||||
|
||||
return UHyperTwistSkillCoreLibrary::DeriveSkillAuthoringHarnessState(
|
||||
RegistryState,
|
||||
ControlState,
|
||||
AuditLedgerState
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryIntegrityReport UHyperTwistContractLibrary::MakeSampleTrainingRepositoryIntegrityReport()
|
||||
{
|
||||
FHyperTwistTrainingRepositoryState RepositoryState = MakeSampleTrainingRepositoryState();
|
||||
|
|
@ -5133,6 +5154,15 @@ FString UHyperTwistContractLibrary::SerializeSkillAuditLedgerStateToJson(
|
|||
);
|
||||
}
|
||||
|
||||
FString UHyperTwistContractLibrary::SerializeSkillAuthoringHarnessStateToJson(
|
||||
const FHyperTwistSkillAuthoringHarnessState& SkillAuthoringHarnessState
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::SerializeStructToJson(
|
||||
SkillAuthoringHarnessState
|
||||
);
|
||||
}
|
||||
|
||||
FString UHyperTwistContractLibrary::SerializeTrainingTimerExportPacketToJson(
|
||||
const FHyperTwistTrainingTimerExportPacket& TimerExportPacket
|
||||
)
|
||||
|
|
@ -5288,6 +5318,17 @@ bool UHyperTwistContractLibrary::DeserializeSkillAuditLedgerStateFromJson(
|
|||
);
|
||||
}
|
||||
|
||||
bool UHyperTwistContractLibrary::DeserializeSkillAuthoringHarnessStateFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistSkillAuthoringHarnessState& OutSkillAuthoringHarnessState
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::DeserializeStructFromJson(
|
||||
Json,
|
||||
OutSkillAuthoringHarnessState
|
||||
);
|
||||
}
|
||||
|
||||
bool UHyperTwistContractLibrary::DeserializeTrainingTimerExportPacketFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingTimerExportPacket& OutTimerExportPacket
|
||||
|
|
|
|||
|
|
@ -517,6 +517,165 @@ namespace HyperTwistSkillCoreLibraryInternal
|
|||
|
||||
return Record;
|
||||
}
|
||||
|
||||
FHyperTwistSkillAuthoringTemplateField MakeAuthoringField(
|
||||
const TCHAR* FieldId,
|
||||
const TCHAR* DisplayLabel,
|
||||
const TCHAR* ExpectedSource,
|
||||
const TCHAR* ExampleValue,
|
||||
const TCHAR* Summary
|
||||
)
|
||||
{
|
||||
FHyperTwistSkillAuthoringTemplateField Field;
|
||||
Field.FieldId = FieldId;
|
||||
Field.DisplayLabel = DisplayLabel;
|
||||
Field.ExpectedSource = ExpectedSource;
|
||||
Field.ExampleValue = ExampleValue;
|
||||
Field.bRequired = true;
|
||||
Field.Summary = Summary;
|
||||
return Field;
|
||||
}
|
||||
|
||||
FHyperTwistSkillAuthoringTemplateSection MakeAuthoringSection(
|
||||
const TCHAR* SectionId,
|
||||
const TCHAR* DisplayLabel,
|
||||
const TArray<FHyperTwistSkillAuthoringTemplateField>& Fields,
|
||||
const TCHAR* Summary
|
||||
)
|
||||
{
|
||||
FHyperTwistSkillAuthoringTemplateSection Section;
|
||||
Section.SectionId = SectionId;
|
||||
Section.DisplayLabel = DisplayLabel;
|
||||
Section.Fields = Fields;
|
||||
Section.bRequiredForAllSkills = true;
|
||||
Section.Summary = Summary;
|
||||
return Section;
|
||||
}
|
||||
|
||||
const FHyperTwistSkillInvocationRecord* FindInvocationRecordBySkillId(
|
||||
const FHyperTwistSkillAuditLedgerState& AuditLedgerState,
|
||||
const FString& SkillId
|
||||
)
|
||||
{
|
||||
return AuditLedgerState.InvocationRecords.FindByPredicate(
|
||||
[&SkillId](const FHyperTwistSkillInvocationRecord& Record)
|
||||
{
|
||||
return Record.SkillId == SkillId;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
FString MakeAuthoringExampleId(const FString& SkillId)
|
||||
{
|
||||
return TEXT("skill-authoring-example/") + MakeInvocationSlug(SkillId);
|
||||
}
|
||||
|
||||
TArray<FString> MakeRequiredAuthoringSectionIds()
|
||||
{
|
||||
return {
|
||||
TEXT("section/skill-identity-owner"),
|
||||
TEXT("section/skill-command-binding"),
|
||||
TEXT("section/skill-permission-provenance"),
|
||||
TEXT("section/skill-off-state"),
|
||||
TEXT("section/skill-invocation-audit"),
|
||||
TEXT("section/skill-validation-contract")
|
||||
};
|
||||
}
|
||||
|
||||
FHyperTwistSkillAuthoringExampleState MakeAuthoringExampleState(
|
||||
const FHyperTwistSkillManifestEntry& Entry,
|
||||
const FHyperTwistSkillAuditLedgerState& AuditLedgerState
|
||||
)
|
||||
{
|
||||
FHyperTwistSkillAuthoringExampleState ExampleState;
|
||||
ExampleState.ExampleId = MakeAuthoringExampleId(Entry.SkillId);
|
||||
ExampleState.SkillId = Entry.SkillId;
|
||||
ExampleState.ExampleLabel = Entry.DisplayLabel + TEXT(" Example");
|
||||
ExampleState.ExampleCommandSurfaceId = Entry.CommandBindings[0].CommandSurfaceId;
|
||||
ExampleState.ExampleArtifactKind = Entry.Provenance.ProducedArtifactKinds[0];
|
||||
ExampleState.TemplateSectionIds = MakeRequiredAuthoringSectionIds();
|
||||
ExampleState.bGroundedInRegistry = true;
|
||||
ExampleState.bHasTraceableAuditExample =
|
||||
FindInvocationRecordBySkillId(AuditLedgerState, Entry.SkillId) != nullptr;
|
||||
ExampleState.Summary =
|
||||
TEXT("First-party authoring example grounded in the current skill registry.");
|
||||
return ExampleState;
|
||||
}
|
||||
|
||||
EHyperTwistSkillValidationExecutionMode DetermineSmokeExecutionMode(
|
||||
const EHyperTwistSkillStatus Status
|
||||
)
|
||||
{
|
||||
switch (Status)
|
||||
{
|
||||
case EHyperTwistSkillStatus::ImplementedNow:
|
||||
return EHyperTwistSkillValidationExecutionMode::LiveContract;
|
||||
case EHyperTwistSkillStatus::CommandContractPending:
|
||||
case EHyperTwistSkillStatus::CleanRoomSpecPending:
|
||||
return EHyperTwistSkillValidationExecutionMode::DeclarationOnly;
|
||||
case EHyperTwistSkillStatus::PlaceholderFamily:
|
||||
return EHyperTwistSkillValidationExecutionMode::PlaceholderStructureOnly;
|
||||
default:
|
||||
return EHyperTwistSkillValidationExecutionMode::None;
|
||||
}
|
||||
}
|
||||
|
||||
EHyperTwistSkillValidationExecutionMode DetermineEvalExecutionMode(
|
||||
const EHyperTwistSkillStatus Status
|
||||
)
|
||||
{
|
||||
switch (Status)
|
||||
{
|
||||
case EHyperTwistSkillStatus::ImplementedNow:
|
||||
return EHyperTwistSkillValidationExecutionMode::LiveContract;
|
||||
case EHyperTwistSkillStatus::CommandContractPending:
|
||||
return EHyperTwistSkillValidationExecutionMode::DeferredUntilWrapper;
|
||||
case EHyperTwistSkillStatus::CleanRoomSpecPending:
|
||||
return EHyperTwistSkillValidationExecutionMode::DeferredUntilCleanRoomSpec;
|
||||
case EHyperTwistSkillStatus::PlaceholderFamily:
|
||||
return EHyperTwistSkillValidationExecutionMode::PlaceholderStructureOnly;
|
||||
default:
|
||||
return EHyperTwistSkillValidationExecutionMode::None;
|
||||
}
|
||||
}
|
||||
|
||||
FString MakeValidationCaseId(
|
||||
const FString& SkillId,
|
||||
const EHyperTwistSkillValidationContractKind Kind
|
||||
)
|
||||
{
|
||||
return FString::Printf(
|
||||
TEXT("skill-validation/%s/%s"),
|
||||
*MakeInvocationSlug(SkillId),
|
||||
Kind == EHyperTwistSkillValidationContractKind::Smoke ? TEXT("smoke") : TEXT("eval")
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistSkillValidationContractCase MakeValidationContractCase(
|
||||
const FHyperTwistSkillManifestEntry& Entry,
|
||||
const EHyperTwistSkillValidationContractKind Kind,
|
||||
const EHyperTwistSkillValidationExecutionMode ExecutionMode,
|
||||
const FHyperTwistSkillAuditLedgerState& AuditLedgerState
|
||||
)
|
||||
{
|
||||
FHyperTwistSkillValidationContractCase ValidationCase;
|
||||
ValidationCase.CaseId = MakeValidationCaseId(Entry.SkillId, Kind);
|
||||
ValidationCase.SkillId = Entry.SkillId;
|
||||
ValidationCase.Kind = Kind;
|
||||
ValidationCase.ExecutionMode = ExecutionMode;
|
||||
ValidationCase.ExpectedCommandSurfaceId = Entry.CommandBindings[0].CommandSurfaceId;
|
||||
ValidationCase.ExpectedServiceBindingId = Entry.CommandBindings[0].ServiceBindingId;
|
||||
ValidationCase.RequiredTemplateSectionIds = MakeRequiredAuthoringSectionIds();
|
||||
ValidationCase.ExpectedArtifactKinds = Entry.Provenance.ProducedArtifactKinds;
|
||||
ValidationCase.bUsesAuditLedgerEvidence =
|
||||
ExecutionMode == EHyperTwistSkillValidationExecutionMode::LiveContract
|
||||
&& FindInvocationRecordBySkillId(AuditLedgerState, Entry.SkillId) != nullptr;
|
||||
ValidationCase.Summary =
|
||||
Kind == EHyperTwistSkillValidationContractKind::Smoke
|
||||
? TEXT("Per-skill smoke validation contract under the current skillization substrate.")
|
||||
: TEXT("Per-skill eval validation contract under the current skillization substrate.");
|
||||
return ValidationCase;
|
||||
}
|
||||
}
|
||||
|
||||
FHyperTwistSkillRegistryState UHyperTwistSkillCoreLibrary::DeriveSkillRegistryState()
|
||||
|
|
@ -946,3 +1105,213 @@ FHyperTwistSkillAuditLedgerState UHyperTwistSkillCoreLibrary::DeriveSkillAuditLe
|
|||
|
||||
return AuditLedgerState;
|
||||
}
|
||||
|
||||
FHyperTwistSkillAuthoringHarnessState UHyperTwistSkillCoreLibrary::DeriveSkillAuthoringHarnessState(
|
||||
const FHyperTwistSkillRegistryState& RegistryState,
|
||||
const FHyperTwistSkillControlState& ControlState,
|
||||
const FHyperTwistSkillAuditLedgerState& AuditLedgerState
|
||||
)
|
||||
{
|
||||
using namespace HyperTwistSkillCoreLibraryInternal;
|
||||
|
||||
if (!RegistryState.IsStructurallyValid()
|
||||
|| !ControlState.IsStructurallyValid()
|
||||
|| !AuditLedgerState.IsStructurallyValid()
|
||||
|| RegistryState.RegistryId != ControlState.RegistryId
|
||||
|| RegistryState.RegistryId != AuditLedgerState.RegistryId)
|
||||
{
|
||||
return FHyperTwistSkillAuthoringHarnessState();
|
||||
}
|
||||
|
||||
FHyperTwistSkillAuthoringHarnessState HarnessState;
|
||||
HarnessState.RegistryId = RegistryState.RegistryId;
|
||||
HarnessState.ManifestVersion = TEXT("s1d-v1");
|
||||
HarnessState.ReferenceUtc = TEXT("2026-05-28T23:20:00Z");
|
||||
HarnessState.CommandSurfaceRootId = RegistryState.CommandSurfaceRootId;
|
||||
HarnessState.AuditLedgerId = AuditLedgerState.LedgerId;
|
||||
HarnessState.TemplateVersion = TEXT("skill-authoring-template-v1");
|
||||
HarnessState.SkillCount = RegistryState.SkillCount;
|
||||
HarnessState.bNewSkillsCanBeAddedWithoutInventingStructure = true;
|
||||
HarnessState.bEverySkillHasSmokeContract = true;
|
||||
HarnessState.bEverySkillHasEvalContract = true;
|
||||
HarnessState.bExamplesGroundedInFirstPartyRegistry = true;
|
||||
HarnessState.bValidationHarnessUsesAuditLedgerWhenLive = true;
|
||||
HarnessState.Summary =
|
||||
TEXT("First-party skill authoring template, examples, and validation-harness contract.");
|
||||
|
||||
HarnessState.TemplateSections = {
|
||||
MakeAuthoringSection(
|
||||
TEXT("section/skill-identity-owner"),
|
||||
TEXT("Identity And Ownership"),
|
||||
{
|
||||
MakeAuthoringField(
|
||||
TEXT("field/skill-id"),
|
||||
TEXT("Skill Id"),
|
||||
TEXT("registry/manifest"),
|
||||
TEXT("skill/skillization-governance"),
|
||||
TEXT("Stable first-party identifier for the skill.")
|
||||
),
|
||||
MakeAuthoringField(
|
||||
TEXT("field/owner-lane-feature"),
|
||||
TEXT("Owner Lane And Feature"),
|
||||
TEXT("registry/manifest"),
|
||||
TEXT("lane/skillization/substrate -> feature/skills/registry-governance"),
|
||||
TEXT("Links the skill back to its owning product lane and feature.")
|
||||
)
|
||||
},
|
||||
TEXT("Required identity and ownership fields for every first-party skill.")
|
||||
),
|
||||
MakeAuthoringSection(
|
||||
TEXT("section/skill-command-binding"),
|
||||
TEXT("Command And Service Binding"),
|
||||
{
|
||||
MakeAuthoringField(
|
||||
TEXT("field/command-surface-id"),
|
||||
TEXT("Command Surface Id"),
|
||||
TEXT("registry/manifest"),
|
||||
TEXT("command/skills/inspect-registry"),
|
||||
TEXT("Stable product-owned command surface for the skill.")
|
||||
),
|
||||
MakeAuthoringField(
|
||||
TEXT("field/service-binding-id"),
|
||||
TEXT("Service Binding Id"),
|
||||
TEXT("registry/manifest"),
|
||||
TEXT("service/skills/registry-state"),
|
||||
TEXT("First-party service or deferred wrapper binding declared for the skill.")
|
||||
)
|
||||
},
|
||||
TEXT("Required command and service binding fields for every first-party skill.")
|
||||
),
|
||||
MakeAuthoringSection(
|
||||
TEXT("section/skill-permission-provenance"),
|
||||
TEXT("Permission And Provenance"),
|
||||
{
|
||||
MakeAuthoringField(
|
||||
TEXT("field/permission-scope"),
|
||||
TEXT("Permission Scope"),
|
||||
TEXT("registry/manifest"),
|
||||
TEXT("scope/skills/governance"),
|
||||
TEXT("Declared state access and assistive permissions.")
|
||||
),
|
||||
MakeAuthoringField(
|
||||
TEXT("field/artifact-kind"),
|
||||
TEXT("Produced Artifact Kind"),
|
||||
TEXT("registry/manifest"),
|
||||
TEXT("artifact/skill-registry-state"),
|
||||
TEXT("Declared provenance-visible output kind for the skill.")
|
||||
)
|
||||
},
|
||||
TEXT("Required permission and provenance fields for every first-party skill.")
|
||||
),
|
||||
MakeAuthoringSection(
|
||||
TEXT("section/skill-off-state"),
|
||||
TEXT("Off-State And Visibility"),
|
||||
{
|
||||
MakeAuthoringField(
|
||||
TEXT("field/enable-settings-key"),
|
||||
TEXT("Enable Settings Key"),
|
||||
TEXT("control-state"),
|
||||
TEXT("skills.enabled.skill.skillization.governance"),
|
||||
TEXT("Durable enable/disable control key for the skill.")
|
||||
),
|
||||
MakeAuthoringField(
|
||||
TEXT("field/visibility-group"),
|
||||
TEXT("Visibility Group"),
|
||||
TEXT("control-state"),
|
||||
TEXT("skill-group/substrate-governance"),
|
||||
TEXT("Family visibility grouping and off-state exposure contract.")
|
||||
)
|
||||
},
|
||||
TEXT("Required off-state and visibility fields for every first-party skill.")
|
||||
),
|
||||
MakeAuthoringSection(
|
||||
TEXT("section/skill-invocation-audit"),
|
||||
TEXT("Invocation And Audit"),
|
||||
{
|
||||
MakeAuthoringField(
|
||||
TEXT("field/invocation-id"),
|
||||
TEXT("Invocation Id"),
|
||||
TEXT("audit-ledger"),
|
||||
TEXT("skill-invocation/skill-skillization-governance/00"),
|
||||
TEXT("Traceable invocation identity for live skill output.")
|
||||
),
|
||||
MakeAuthoringField(
|
||||
TEXT("field/outcome-recording"),
|
||||
TEXT("Outcome Recording"),
|
||||
TEXT("audit-ledger"),
|
||||
TEXT("Succeeded / Failed / Cancelled"),
|
||||
TEXT("Outcome recording contract required for traceability.")
|
||||
)
|
||||
},
|
||||
TEXT("Required invocation and audit fields for every first-party skill.")
|
||||
),
|
||||
MakeAuthoringSection(
|
||||
TEXT("section/skill-validation-contract"),
|
||||
TEXT("Validation Contract"),
|
||||
{
|
||||
MakeAuthoringField(
|
||||
TEXT("field/smoke-contract"),
|
||||
TEXT("Smoke Contract"),
|
||||
TEXT("validation-harness"),
|
||||
TEXT("LiveContract / DeclarationOnly / PlaceholderStructureOnly"),
|
||||
TEXT("Per-skill smoke validation mode.")
|
||||
),
|
||||
MakeAuthoringField(
|
||||
TEXT("field/eval-contract"),
|
||||
TEXT("Eval Contract"),
|
||||
TEXT("validation-harness"),
|
||||
TEXT("LiveContract / DeferredUntilWrapper / DeferredUntilCleanRoomSpec"),
|
||||
TEXT("Per-skill eval validation mode.")
|
||||
)
|
||||
},
|
||||
TEXT("Required validation-harness fields for every first-party skill.")
|
||||
)
|
||||
};
|
||||
|
||||
for (const FHyperTwistSkillManifestEntry& Entry : RegistryState.Entries)
|
||||
{
|
||||
const FHyperTwistSkillAuthoringExampleState ExampleState =
|
||||
MakeAuthoringExampleState(Entry, AuditLedgerState);
|
||||
if (!ExampleState.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistSkillAuthoringHarnessState();
|
||||
}
|
||||
|
||||
const FHyperTwistSkillValidationContractCase SmokeCase =
|
||||
MakeValidationContractCase(
|
||||
Entry,
|
||||
EHyperTwistSkillValidationContractKind::Smoke,
|
||||
DetermineSmokeExecutionMode(Entry.Status),
|
||||
AuditLedgerState
|
||||
);
|
||||
const FHyperTwistSkillValidationContractCase EvalCase =
|
||||
MakeValidationContractCase(
|
||||
Entry,
|
||||
EHyperTwistSkillValidationContractKind::Eval,
|
||||
DetermineEvalExecutionMode(Entry.Status),
|
||||
AuditLedgerState
|
||||
);
|
||||
if (!SmokeCase.IsStructurallyValid() || !EvalCase.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistSkillAuthoringHarnessState();
|
||||
}
|
||||
|
||||
HarnessState.Examples.Add(ExampleState);
|
||||
HarnessState.ValidationCases.Add(SmokeCase);
|
||||
HarnessState.ValidationCases.Add(EvalCase);
|
||||
HarnessState.SkillsWithSmokeContractCount += 1;
|
||||
HarnessState.SkillsWithEvalContractCount += 1;
|
||||
HarnessState.bExamplesGroundedInFirstPartyRegistry &= ExampleState.bGroundedInRegistry;
|
||||
HarnessState.bValidationHarnessUsesAuditLedgerWhenLive &=
|
||||
SmokeCase.ExecutionMode != EHyperTwistSkillValidationExecutionMode::LiveContract
|
||||
|| SmokeCase.bUsesAuditLedgerEvidence;
|
||||
HarnessState.bValidationHarnessUsesAuditLedgerWhenLive &=
|
||||
EvalCase.ExecutionMode != EHyperTwistSkillValidationExecutionMode::LiveContract
|
||||
|| EvalCase.bUsesAuditLedgerEvidence;
|
||||
}
|
||||
|
||||
HarnessState.ExampleCount = HarnessState.Examples.Num();
|
||||
HarnessState.ValidationCaseCount = HarnessState.ValidationCases.Num();
|
||||
|
||||
return HarnessState;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,9 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Skills")
|
||||
static FHyperTwistSkillAuditLedgerState MakeSampleSkillAuditLedgerState();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Skills")
|
||||
static FHyperTwistSkillAuthoringHarnessState MakeSampleSkillAuthoringHarnessState();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
static FHyperTwistTrainingRepositoryIntegrityReport MakeSampleTrainingRepositoryIntegrityReport();
|
||||
|
||||
|
|
@ -380,6 +383,11 @@ public:
|
|||
const FHyperTwistSkillAuditLedgerState& SkillAuditLedgerState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization")
|
||||
static FString SerializeSkillAuthoringHarnessStateToJson(
|
||||
const FHyperTwistSkillAuthoringHarnessState& SkillAuthoringHarnessState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization")
|
||||
static FString SerializeTrainingTimerExportPacketToJson(const FHyperTwistTrainingTimerExportPacket& TimerExportPacket);
|
||||
|
||||
|
|
@ -470,6 +478,12 @@ public:
|
|||
FHyperTwistSkillAuditLedgerState& OutSkillAuditLedgerState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization")
|
||||
static bool DeserializeSkillAuthoringHarnessStateFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistSkillAuthoringHarnessState& OutSkillAuthoringHarnessState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization")
|
||||
static bool DeserializeTrainingTimerExportPacketFromJson(const FString& Json, FHyperTwistTrainingTimerExportPacket& OutTimerExportPacket);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,4 +25,11 @@ public:
|
|||
const FHyperTwistSkillRegistryState& RegistryState,
|
||||
const FHyperTwistSkillControlState& ControlState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Skills")
|
||||
static FHyperTwistSkillAuthoringHarnessState DeriveSkillAuthoringHarnessState(
|
||||
const FHyperTwistSkillRegistryState& RegistryState,
|
||||
const FHyperTwistSkillControlState& ControlState,
|
||||
const FHyperTwistSkillAuditLedgerState& AuditLedgerState
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,6 +42,25 @@ enum class EHyperTwistSkillInvocationOutcome : uint8
|
|||
Cancelled UMETA(DisplayName = "Cancelled")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistSkillValidationContractKind : uint8
|
||||
{
|
||||
None UMETA(DisplayName = "None"),
|
||||
Smoke UMETA(DisplayName = "Smoke"),
|
||||
Eval UMETA(DisplayName = "Eval")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistSkillValidationExecutionMode : uint8
|
||||
{
|
||||
None UMETA(DisplayName = "None"),
|
||||
LiveContract UMETA(DisplayName = "Live Contract"),
|
||||
DeclarationOnly UMETA(DisplayName = "Declaration Only"),
|
||||
DeferredUntilWrapper UMETA(DisplayName = "Deferred Until Wrapper"),
|
||||
DeferredUntilCleanRoomSpec UMETA(DisplayName = "Deferred Until Clean-Room Spec"),
|
||||
PlaceholderStructureOnly UMETA(DisplayName = "Placeholder Structure Only")
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSkillCommandBindingDeclaration
|
||||
{
|
||||
|
|
@ -1216,3 +1235,388 @@ struct FHyperTwistSkillAuditLedgerState
|
|||
&& bCommandServiceProvenanceVisible == bComputedCommandProvenanceVisible;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSkillAuthoringTemplateField
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString FieldId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DisplayLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExpectedSource;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExampleValue;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRequired = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Summary;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !FieldId.IsEmpty()
|
||||
&& !DisplayLabel.IsEmpty()
|
||||
&& !ExpectedSource.IsEmpty()
|
||||
&& !ExampleValue.IsEmpty()
|
||||
&& bRequired;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSkillAuthoringTemplateSection
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SectionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DisplayLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistSkillAuthoringTemplateField> Fields;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRequiredForAllSkills = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Summary;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
if (SectionId.IsEmpty()
|
||||
|| DisplayLabel.IsEmpty()
|
||||
|| Fields.Num() == 0
|
||||
|| !bRequiredForAllSkills)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<FString> SeenFieldIds;
|
||||
for (const FHyperTwistSkillAuthoringTemplateField& Field : Fields)
|
||||
{
|
||||
if (!Field.IsStructurallyValid() || SeenFieldIds.Contains(Field.FieldId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SeenFieldIds.Add(Field.FieldId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSkillAuthoringExampleState
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExampleId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SkillId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExampleLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExampleCommandSurfaceId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExampleArtifactKind;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> TemplateSectionIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bGroundedInRegistry = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasTraceableAuditExample = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Summary;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
if (ExampleId.IsEmpty()
|
||||
|| SkillId.IsEmpty()
|
||||
|| ExampleLabel.IsEmpty()
|
||||
|| ExampleCommandSurfaceId.IsEmpty()
|
||||
|| ExampleArtifactKind.IsEmpty()
|
||||
|| TemplateSectionIds.Num() == 0
|
||||
|| !bGroundedInRegistry)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FString& SectionId : TemplateSectionIds)
|
||||
{
|
||||
if (SectionId.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSkillValidationContractCase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SkillId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistSkillValidationContractKind Kind = EHyperTwistSkillValidationContractKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistSkillValidationExecutionMode ExecutionMode = EHyperTwistSkillValidationExecutionMode::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExpectedCommandSurfaceId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExpectedServiceBindingId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> RequiredTemplateSectionIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> ExpectedArtifactKinds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bUsesAuditLedgerEvidence = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Summary;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
if (CaseId.IsEmpty()
|
||||
|| SkillId.IsEmpty()
|
||||
|| Kind == EHyperTwistSkillValidationContractKind::None
|
||||
|| ExecutionMode == EHyperTwistSkillValidationExecutionMode::None
|
||||
|| ExpectedCommandSurfaceId.IsEmpty()
|
||||
|| ExpectedServiceBindingId.IsEmpty()
|
||||
|| RequiredTemplateSectionIds.Num() == 0
|
||||
|| ExpectedArtifactKinds.Num() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FString& SectionId : RequiredTemplateSectionIds)
|
||||
{
|
||||
if (SectionId.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const FString& ArtifactKind : ExpectedArtifactKinds)
|
||||
{
|
||||
if (ArtifactKind.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const bool bLiveMode =
|
||||
ExecutionMode == EHyperTwistSkillValidationExecutionMode::LiveContract;
|
||||
if (bLiveMode && !bUsesAuditLedgerEvidence)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSkillAuthoringHarnessState
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RegistryId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ManifestVersion;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ReferenceUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CommandSurfaceRootId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString AuditLedgerId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateVersion;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistSkillAuthoringTemplateSection> TemplateSections;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistSkillAuthoringExampleState> Examples;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistSkillValidationContractCase> ValidationCases;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SkillCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ExampleCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ValidationCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SkillsWithSmokeContractCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SkillsWithEvalContractCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bNewSkillsCanBeAddedWithoutInventingStructure = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bEverySkillHasSmokeContract = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bEverySkillHasEvalContract = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bExamplesGroundedInFirstPartyRegistry = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bValidationHarnessUsesAuditLedgerWhenLive = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Summary;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
if (RegistryId.IsEmpty()
|
||||
|| ManifestVersion.IsEmpty()
|
||||
|| ReferenceUtc.IsEmpty()
|
||||
|| CommandSurfaceRootId.IsEmpty()
|
||||
|| AuditLedgerId.IsEmpty()
|
||||
|| TemplateVersion.IsEmpty()
|
||||
|| TemplateSections.Num() == 0
|
||||
|| Examples.Num() == 0
|
||||
|| ValidationCases.Num() == 0
|
||||
|| SkillCount <= 0
|
||||
|| ExampleCount != Examples.Num()
|
||||
|| ValidationCaseCount != ValidationCases.Num()
|
||||
|| SkillsWithSmokeContractCount < 0
|
||||
|| SkillsWithEvalContractCount < 0
|
||||
|| !bNewSkillsCanBeAddedWithoutInventingStructure
|
||||
|| !bEverySkillHasSmokeContract
|
||||
|| !bEverySkillHasEvalContract
|
||||
|| !bExamplesGroundedInFirstPartyRegistry
|
||||
|| !bValidationHarnessUsesAuditLedgerWhenLive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<FString> SeenSectionIds;
|
||||
for (const FHyperTwistSkillAuthoringTemplateSection& Section : TemplateSections)
|
||||
{
|
||||
if (!Section.IsStructurallyValid() || SeenSectionIds.Contains(Section.SectionId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SeenSectionIds.Add(Section.SectionId);
|
||||
}
|
||||
|
||||
TArray<FString> SeenExampleIds;
|
||||
TArray<FString> ExampleSkillIds;
|
||||
bool bComputedExamplesGroundedInRegistry = true;
|
||||
for (const FHyperTwistSkillAuthoringExampleState& Example : Examples)
|
||||
{
|
||||
if (!Example.IsStructurallyValid() || SeenExampleIds.Contains(Example.ExampleId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FString& SectionId : Example.TemplateSectionIds)
|
||||
{
|
||||
if (!SeenSectionIds.Contains(SectionId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SeenExampleIds.Add(Example.ExampleId);
|
||||
ExampleSkillIds.Add(Example.SkillId);
|
||||
bComputedExamplesGroundedInRegistry &= Example.bGroundedInRegistry;
|
||||
}
|
||||
|
||||
TArray<FString> SeenCaseIds;
|
||||
TArray<FString> SkillsWithSmokeContract;
|
||||
TArray<FString> SkillsWithEvalContract;
|
||||
bool bComputedValidationUsesAuditLedgerWhenLive = true;
|
||||
for (const FHyperTwistSkillValidationContractCase& ValidationCase : ValidationCases)
|
||||
{
|
||||
if (!ValidationCase.IsStructurallyValid() || SeenCaseIds.Contains(ValidationCase.CaseId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ExampleSkillIds.Contains(ValidationCase.SkillId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FString& SectionId : ValidationCase.RequiredTemplateSectionIds)
|
||||
{
|
||||
if (!SeenSectionIds.Contains(SectionId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ValidationCase.Kind == EHyperTwistSkillValidationContractKind::Smoke)
|
||||
{
|
||||
SkillsWithSmokeContract.AddUnique(ValidationCase.SkillId);
|
||||
}
|
||||
else if (ValidationCase.Kind == EHyperTwistSkillValidationContractKind::Eval)
|
||||
{
|
||||
SkillsWithEvalContract.AddUnique(ValidationCase.SkillId);
|
||||
}
|
||||
|
||||
bComputedValidationUsesAuditLedgerWhenLive &=
|
||||
ValidationCase.ExecutionMode != EHyperTwistSkillValidationExecutionMode::LiveContract
|
||||
|| ValidationCase.bUsesAuditLedgerEvidence;
|
||||
|
||||
SeenCaseIds.Add(ValidationCase.CaseId);
|
||||
}
|
||||
|
||||
return SkillsWithSmokeContractCount == SkillsWithSmokeContract.Num()
|
||||
&& SkillsWithEvalContractCount == SkillsWithEvalContract.Num()
|
||||
&& SkillsWithSmokeContractCount == SkillCount
|
||||
&& SkillsWithEvalContractCount == SkillCount
|
||||
&& bExamplesGroundedInFirstPartyRegistry == bComputedExamplesGroundedInRegistry
|
||||
&& bValidationHarnessUsesAuditLedgerWhenLive
|
||||
== bComputedValidationUsesAuditLedgerWhenLive;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,231 @@
|
|||
#include "Misc/AutomationTest.h"
|
||||
|
||||
#include "HyperTwistBootstrap/HyperTwistContractLibrary.h"
|
||||
|
||||
namespace HyperTwistSkillPhaseS1DTestInternal
|
||||
{
|
||||
const FHyperTwistSkillAuthoringTemplateSection* FindSectionById(
|
||||
const FHyperTwistSkillAuthoringHarnessState& HarnessState,
|
||||
const FString& SectionId
|
||||
)
|
||||
{
|
||||
for (const FHyperTwistSkillAuthoringTemplateSection& Section : HarnessState.TemplateSections)
|
||||
{
|
||||
if (Section.SectionId == SectionId)
|
||||
{
|
||||
return &Section;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const FHyperTwistSkillValidationContractCase* FindValidationCase(
|
||||
const FHyperTwistSkillAuthoringHarnessState& HarnessState,
|
||||
const FString& SkillId,
|
||||
const EHyperTwistSkillValidationContractKind Kind
|
||||
)
|
||||
{
|
||||
for (const FHyperTwistSkillValidationContractCase& ValidationCase : HarnessState.ValidationCases)
|
||||
{
|
||||
if (ValidationCase.SkillId == SkillId && ValidationCase.Kind == Kind)
|
||||
{
|
||||
return &ValidationCase;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistSkillPhaseS1DAuthoringTemplateTest,
|
||||
"HyperTwist.FirstParty.Skill.PhaseS1D.AuthoringTemplate",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistSkillPhaseS1DAuthoringTemplateTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const FHyperTwistSkillAuthoringHarnessState HarnessState =
|
||||
UHyperTwistContractLibrary::MakeSampleSkillAuthoringHarnessState();
|
||||
|
||||
TestTrue(
|
||||
TEXT("Sample skill authoring harness state should be structurally valid."),
|
||||
HarnessState.IsStructurallyValid()
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("New skills should be addable without inventing structure."),
|
||||
HarnessState.bNewSkillsCanBeAddedWithoutInventingStructure
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The sample authoring harness should have one example per current skill."),
|
||||
HarnessState.ExampleCount,
|
||||
HarnessState.SkillCount
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("Examples should stay grounded in the first-party registry."),
|
||||
HarnessState.bExamplesGroundedInFirstPartyRegistry
|
||||
);
|
||||
|
||||
const FHyperTwistSkillAuthoringTemplateSection* ValidationSection =
|
||||
HyperTwistSkillPhaseS1DTestInternal::FindSectionById(
|
||||
HarnessState,
|
||||
TEXT("section/skill-validation-contract")
|
||||
);
|
||||
TestNotNull(
|
||||
TEXT("The sample authoring harness should expose the validation-contract section."),
|
||||
ValidationSection
|
||||
);
|
||||
if (ValidationSection != nullptr)
|
||||
{
|
||||
TestEqual(
|
||||
TEXT("The validation-contract section should carry the expected number of required fields."),
|
||||
ValidationSection->Fields.Num(),
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistSkillPhaseS1DValidationHarnessCoverageTest,
|
||||
"HyperTwist.FirstParty.Skill.PhaseS1D.ValidationHarnessCoverage",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistSkillPhaseS1DValidationHarnessCoverageTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const FHyperTwistSkillAuthoringHarnessState HarnessState =
|
||||
UHyperTwistContractLibrary::MakeSampleSkillAuthoringHarnessState();
|
||||
|
||||
TestTrue(
|
||||
TEXT("Sample skill authoring harness state should be structurally valid."),
|
||||
HarnessState.IsStructurallyValid()
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("Every skill should have a smoke contract."),
|
||||
HarnessState.bEverySkillHasSmokeContract
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("Every skill should have an eval contract."),
|
||||
HarnessState.bEverySkillHasEvalContract
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("Live validation contracts should use audit-ledger evidence."),
|
||||
HarnessState.bValidationHarnessUsesAuditLedgerWhenLive
|
||||
);
|
||||
|
||||
const FHyperTwistSkillValidationContractCase* GovernanceSmoke =
|
||||
HyperTwistSkillPhaseS1DTestInternal::FindValidationCase(
|
||||
HarnessState,
|
||||
TEXT("skill/skillization-governance"),
|
||||
EHyperTwistSkillValidationContractKind::Smoke
|
||||
);
|
||||
TestNotNull(
|
||||
TEXT("The governance skill should have a smoke validation contract."),
|
||||
GovernanceSmoke
|
||||
);
|
||||
if (GovernanceSmoke != nullptr)
|
||||
{
|
||||
TestEqual(
|
||||
TEXT("The governance skill smoke contract should run in live mode."),
|
||||
GovernanceSmoke->ExecutionMode,
|
||||
EHyperTwistSkillValidationExecutionMode::LiveContract
|
||||
);
|
||||
}
|
||||
|
||||
const FHyperTwistSkillValidationContractCase* ReviewEval =
|
||||
HyperTwistSkillPhaseS1DTestInternal::FindValidationCase(
|
||||
HarnessState,
|
||||
TEXT("skill/review-architecture"),
|
||||
EHyperTwistSkillValidationContractKind::Eval
|
||||
);
|
||||
TestNotNull(
|
||||
TEXT("The review skill should have an eval validation contract."),
|
||||
ReviewEval
|
||||
);
|
||||
if (ReviewEval != nullptr)
|
||||
{
|
||||
TestEqual(
|
||||
TEXT("The review skill eval contract should stay deferred until wrappers land."),
|
||||
ReviewEval->ExecutionMode,
|
||||
EHyperTwistSkillValidationExecutionMode::DeferredUntilWrapper
|
||||
);
|
||||
}
|
||||
|
||||
const FHyperTwistSkillValidationContractCase* RouxEval =
|
||||
HyperTwistSkillPhaseS1DTestInternal::FindValidationCase(
|
||||
HarnessState,
|
||||
TEXT("skill/roux-session-review"),
|
||||
EHyperTwistSkillValidationContractKind::Eval
|
||||
);
|
||||
TestNotNull(
|
||||
TEXT("The Roux skill should have an eval validation contract."),
|
||||
RouxEval
|
||||
);
|
||||
if (RouxEval != nullptr)
|
||||
{
|
||||
TestEqual(
|
||||
TEXT("The Roux skill eval contract should stay deferred until a clean-room spec lands."),
|
||||
RouxEval->ExecutionMode,
|
||||
EHyperTwistSkillValidationExecutionMode::DeferredUntilCleanRoomSpec
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistSkillPhaseS1DSerializationRoundTripTest,
|
||||
"HyperTwist.FirstParty.Skill.PhaseS1D.SerializationRoundTrip",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistSkillPhaseS1DSerializationRoundTripTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const FHyperTwistSkillAuthoringHarnessState HarnessState =
|
||||
UHyperTwistContractLibrary::MakeSampleSkillAuthoringHarnessState();
|
||||
|
||||
TestTrue(
|
||||
TEXT("Sample skill authoring harness state should be structurally valid before serialization."),
|
||||
HarnessState.IsStructurallyValid()
|
||||
);
|
||||
|
||||
const FString Json =
|
||||
UHyperTwistContractLibrary::SerializeSkillAuthoringHarnessStateToJson(HarnessState);
|
||||
TestTrue(
|
||||
TEXT("Serialized skill authoring harness JSON should include the structural-addition guard field."),
|
||||
Json.Contains(TEXT("bNewSkillsCanBeAddedWithoutInventingStructure"))
|
||||
);
|
||||
|
||||
FHyperTwistSkillAuthoringHarnessState RoundTrippedState;
|
||||
TestTrue(
|
||||
TEXT("Deserializing the skill authoring harness JSON should succeed."),
|
||||
UHyperTwistContractLibrary::DeserializeSkillAuthoringHarnessStateFromJson(
|
||||
Json,
|
||||
RoundTrippedState
|
||||
)
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("Round-tripped skill authoring harness state should remain structurally valid."),
|
||||
RoundTrippedState.IsStructurallyValid()
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("Round-tripped example count should match the original sample."),
|
||||
RoundTrippedState.ExampleCount,
|
||||
HarnessState.ExampleCount
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("Round-tripped validation-case count should match the original sample."),
|
||||
RoundTrippedState.ValidationCaseCount,
|
||||
HarnessState.ValidationCaseCount
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("Round-tripped smoke coverage should match the original sample."),
|
||||
RoundTrippedState.SkillsWithSmokeContractCount,
|
||||
HarnessState.SkillsWithSmokeContractCount
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
# HyperTwist Phase S1-D first-party skill authoring, examples, and validation harness implementation packet
|
||||
|
||||
Created on `2026-05-28`
|
||||
|
||||
## Status
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- bounded `Phase S1-D` implementation slice
|
||||
|
||||
## Purpose
|
||||
|
||||
This packet lands the bounded first-party skill authoring, examples, and
|
||||
validation-harness seam under the canonical `Skillization And Command Surface`
|
||||
doctrine.
|
||||
|
||||
The landed slice is:
|
||||
|
||||
- first-party skill authoring template
|
||||
- registry-grounded examples
|
||||
- per-skill smoke/eval validation harness
|
||||
|
||||
It is not:
|
||||
|
||||
- permissive analyzer wrappers
|
||||
- restrictive clean-room command-contract specs
|
||||
- wrapper execution or donor command promotion
|
||||
|
||||
## Current authority basis
|
||||
|
||||
This implementation packet stands on:
|
||||
|
||||
- `docs/ops/HYPERTWIST_SKILLIZATION_AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md`
|
||||
- `docs/ops/HYPERTWIST_OPTIONAL_ASSISTIVE_FEATURE_DEACTIVATION_AND_REMOVABILITY_DOCTRINE_2026-05-21.md`
|
||||
- `docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/SKILLS.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/PROVENANCE_AND_TRUST_MODEL.md`
|
||||
- `docs/arch/HYPERTWIST_PHASES1_D_FIRST_PARTY_SKILL_AUTHORING_EXAMPLES_AND_VALIDATION_HARNESS_PREPARATION_PACKET_2026-05-28.md`
|
||||
|
||||
The preserved owners do not change:
|
||||
|
||||
- first-party HyperTwist remains the owner of the product command surface
|
||||
- the landed `Phase S1-A`, `Phase S1-B`, and `Phase S1-C` seams remain the
|
||||
current authoritative substrate beneath this packet
|
||||
- optional assistive skills remain product-owned adjunct declarations rather
|
||||
than donor command truth
|
||||
|
||||
## Landed scope
|
||||
|
||||
The current code now owns a bounded first-party authoring-harness seam through:
|
||||
|
||||
- canonical authoring-template field, section, example, validation-contract,
|
||||
and aggregate harness types in:
|
||||
- `HyperTwistSkillTypes.h`
|
||||
- first-party authoring-harness derivation over the landed `S1-A` registry,
|
||||
`S1-B` control-state, and `S1-C` audit-ledger seams in:
|
||||
- `UHyperTwistSkillCoreLibrary`
|
||||
- current bounded harness coverage for:
|
||||
- reusable skill authoring-template sections
|
||||
- registry-grounded per-skill examples
|
||||
- per-skill smoke/eval validation-contract cases
|
||||
- live, declaration-only, deferred-wrapper, deferred-clean-room, and
|
||||
placeholder validation modes
|
||||
- structural-addition guard state proving new skills can be added without
|
||||
inventing fresh format
|
||||
- sample contract helpers in:
|
||||
- `UHyperTwistContractLibrary::MakeSampleSkillAuthoringHarnessState()`
|
||||
- `UHyperTwistContractLibrary::SerializeSkillAuthoringHarnessStateToJson(...)`
|
||||
- `UHyperTwistContractLibrary::DeserializeSkillAuthoringHarnessStateFromJson(...)`
|
||||
- focused automation coverage in:
|
||||
- `HyperTwistSkillPhaseS1DAuthoringValidationHarnessContractTest.cpp`
|
||||
|
||||
## Why this is still intentionally bounded
|
||||
|
||||
This packet lands authoring-template, examples, and validation-harness
|
||||
contracts only.
|
||||
|
||||
Still deferred:
|
||||
|
||||
- permissive analyzer wrappers
|
||||
- restrictive clean-room command-contract specs
|
||||
|
||||
## Validation
|
||||
|
||||
Build validation:
|
||||
|
||||
- `UnrealHyperTwistEditor Win64 Development`
|
||||
|
||||
Focused automation validation:
|
||||
|
||||
- `HyperTwist.FirstParty.Skill.PhaseS1D.AuthoringTemplate`
|
||||
- `HyperTwist.FirstParty.Skill.PhaseS1D.ValidationHarnessCoverage`
|
||||
- `HyperTwist.FirstParty.Skill.PhaseS1D.SerializationRoundTrip`
|
||||
|
||||
Observed:
|
||||
|
||||
- `3` focused `Phase S1-D` automation tests succeeded
|
||||
|
||||
## Queue effect
|
||||
|
||||
This packet consumes the current `Phase S1-D` implementation slice.
|
||||
|
||||
After this landing:
|
||||
|
||||
- `S1-D` is landed in current code
|
||||
- `S2-A` is the next clean skillization move
|
||||
- do not jump straight from `S1-D` to restrictive command specs
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
# HyperTwist Phase S1-D first-party skill authoring, examples, and validation harness preparation packet
|
||||
|
||||
Created on `2026-05-28`
|
||||
|
||||
## Status
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- source-backed `Phase S1-D` preparation/control slice
|
||||
|
||||
## Purpose
|
||||
|
||||
This packet scopes the fourth bounded product implementation slice under the
|
||||
canonical `Skillization And Command Surface` doctrine.
|
||||
|
||||
The granted slice is:
|
||||
|
||||
- first-party skill authoring template
|
||||
- registry-grounded examples
|
||||
- per-skill smoke/eval validation harness
|
||||
|
||||
It is not:
|
||||
|
||||
- permissive analyzer wrappers
|
||||
- restrictive clean-room command-contract specs
|
||||
- wrapper execution or donor command promotion
|
||||
|
||||
## Current authority basis
|
||||
|
||||
This control pass stands on:
|
||||
|
||||
- `docs/ops/HYPERTWIST_SKILLIZATION_AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md`
|
||||
- `docs/ops/HYPERTWIST_OPTIONAL_ASSISTIVE_FEATURE_DEACTIVATION_AND_REMOVABILITY_DOCTRINE_2026-05-21.md`
|
||||
- `docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/SKILLS.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/PROVENANCE_AND_TRUST_MODEL.md`
|
||||
- `docs/arch/HYPERTWIST_PHASES1_A_FIRST_PARTY_SKILL_REGISTRY_AND_MANIFEST_CONTRACT_IMPLEMENTATION_PACKET_2026-05-28.md`
|
||||
- `docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_IMPLEMENTATION_PACKET_2026-05-28.md`
|
||||
- `docs/arch/HYPERTWIST_PHASES1_C_FIRST_PARTY_SKILL_INVOCATION_PROVENANCE_AND_AUDIT_LEDGER_IMPLEMENTATION_PACKET_2026-05-28.md`
|
||||
|
||||
The preserved owners do not change here:
|
||||
|
||||
- first-party HyperTwist remains the owner of the product command surface
|
||||
- the landed `Phase S1-A`, `Phase S1-B`, and `Phase S1-C` seams remain the
|
||||
authoritative substrate beneath this packet
|
||||
- optional assistive skills remain product-owned adjuncts rather than donor
|
||||
command truth
|
||||
|
||||
## Granted family
|
||||
|
||||
The bounded `Phase S1-D` slice may land:
|
||||
|
||||
1. first-party skill authoring-template sections and required fields
|
||||
2. first-party registry-grounded authoring examples
|
||||
3. first-party per-skill smoke/eval validation-contract cases
|
||||
4. bounded sample authoring-harness derivation and JSON round-trip coverage
|
||||
|
||||
The packet must stay out of:
|
||||
|
||||
- permissive analyzer wrapper execution
|
||||
- restrictive clean-room command specs
|
||||
- broader domain skill widening
|
||||
|
||||
## Proposed implementation shape
|
||||
|
||||
Land the narrower first-party boundary through:
|
||||
|
||||
- new skill types for:
|
||||
- authoring-template fields and sections
|
||||
- registry-grounded examples
|
||||
- validation-contract kind and execution mode
|
||||
- per-skill validation cases
|
||||
- bounded authoring-harness aggregate
|
||||
- a first-party skill-core derivation function over the landed `S1-A`,
|
||||
`S1-B`, and `S1-C` seams
|
||||
- sample-contract helpers for:
|
||||
- authoring-harness derivation
|
||||
- JSON serialization
|
||||
- JSON deserialization
|
||||
- focused automation in:
|
||||
- `HyperTwistSkillPhaseS1DAuthoringValidationHarnessContractTest.cpp`
|
||||
|
||||
## Validation target
|
||||
|
||||
Validate with:
|
||||
|
||||
- Unreal build for `UnrealHyperTwistEditor Win64 Development`
|
||||
- focused automation:
|
||||
- `HyperTwist.FirstParty.Skill.PhaseS1D.AuthoringTemplate`
|
||||
- `HyperTwist.FirstParty.Skill.PhaseS1D.ValidationHarnessCoverage`
|
||||
- `HyperTwist.FirstParty.Skill.PhaseS1D.SerializationRoundTrip`
|
||||
|
||||
## Queue effect
|
||||
|
||||
If this packet lands cleanly:
|
||||
|
||||
- `S1-D` is consumed
|
||||
- `S2-A` becomes the next clean move
|
||||
- do not jump straight from `S1-D` to restrictive specs
|
||||
|
|
@ -277,6 +277,7 @@ Specifically:
|
|||
is now landed in current code
|
||||
- the bounded first-party `Phase S1-C` invocation/provenance/audit-ledger
|
||||
packet is now landed in current code
|
||||
- `S1-D` authoring/examples/validation-harness expansion is the next clean move
|
||||
- `S2-A` permissive analyzer wrappers stay deferred until `S1-D` lands
|
||||
- the bounded first-party `Phase S1-D` authoring/examples/validation-harness
|
||||
packet is now landed in current code
|
||||
- `S2-A` permissive analyzer wrappers are the next clean move
|
||||
- `S2-B` clean-room command-contract specs stay deferred until `S2-A`
|
||||
|
|
|
|||
|
|
@ -245,7 +245,8 @@ Current state:
|
|||
|
||||
- the bounded first-party `Phase S1-C` invocation/provenance/audit-ledger
|
||||
packet is now landed in current code
|
||||
- authoring/examples/validation-harness expansion remains deferred to `S1-D`
|
||||
- the bounded first-party `Phase S1-D` authoring/examples/validation-harness
|
||||
packet is now landed in current code
|
||||
- analyzer wrappers remain deferred to `S2-A`
|
||||
|
||||
#### `S1-D` authoring, examples, and validation harness
|
||||
|
|
@ -260,6 +261,13 @@ Acceptance gates:
|
|||
|
||||
- new skills can be added without inventing structure
|
||||
|
||||
Current state:
|
||||
|
||||
- the bounded first-party `Phase S1-D` authoring/examples/validation-harness
|
||||
packet is now landed in current code
|
||||
- analyzer wrappers remain deferred to `S2-A`
|
||||
- restrictive clean-room command-contract specs remain deferred to `S2-B`
|
||||
|
||||
### S2 - refactor and analyzer skills
|
||||
|
||||
Start with the highest-leverage engineering/tooling family.
|
||||
|
|
@ -473,9 +481,8 @@ These are target-shape command families, not claims of implemented reality.
|
|||
|
||||
The next correct sequence is:
|
||||
|
||||
1. `S1-D` authoring, examples, and validation harness
|
||||
2. `S2-A` permissive analyzer wrappers
|
||||
3. `S2-B` clean-room command-contract specs for restrictive lanes
|
||||
1. `S2-A` permissive analyzer wrappers
|
||||
2. `S2-B` clean-room command-contract specs for restrictive lanes
|
||||
|
||||
Broader memory, browser, workflow, provider, and domain skill widening should
|
||||
wait until that base exists.
|
||||
|
|
|
|||
|
|
@ -242,4 +242,7 @@ Future skill growth must follow:
|
|||
- the bounded first-party `Phase S1-C` invocation/provenance/audit-ledger
|
||||
seam is now the live product base for traceable skill output, failure, and
|
||||
cancel recording
|
||||
- `S1-D` remains the next clean move before any wrapper widening
|
||||
- the bounded first-party `Phase S1-D` authoring/examples/validation-harness
|
||||
seam is now the live product base for adding new skills without inventing
|
||||
fresh structure
|
||||
- `S2-A` remains the next clean move before wrapper widening
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ repo.
|
|||
|
||||
| Feature | Status | Primary authority | Notes |
|
||||
|---|---|---|---|
|
||||
| First-party skill registry and enable/disable governance | Implemented now | landed first-party `Phase S1-A`, `Phase S1-B`, and `Phase S1-C` packets | Current bounded first-party skill status/family contracts, command/service binding declarations, permission/scope declarations, provenance/log declarations, manifest entries, registry counts, durable master-switch/per-skill control-state, family visibility groups, disabled-but-installed inert-off-state truth, invocation-record format, command/service provenance, and failure/cancel audit-ledger storage are live. Authoring/examples/validation-harness expansion remains the next bounded skillization seam. |
|
||||
| First-party skill registry and enable/disable governance | Implemented now | landed first-party `Phase S1-A`, `Phase S1-B`, `Phase S1-C`, and `Phase S1-D` packets | Current bounded first-party skill status/family contracts, command/service binding declarations, permission/scope declarations, provenance/log declarations, manifest entries, registry counts, durable master-switch/per-skill control-state, family visibility groups, disabled-but-installed inert-off-state truth, invocation-record format, command/service provenance, failure/cancel audit-ledger storage, authoring-template sections, registry-grounded examples, and per-skill smoke/eval validation-harness contracts are live. Permissive analyzer wrappers remain the next bounded skillization seam. |
|
||||
| Review/analyzer skill family | Deep-source grounded retained | skillization doctrine | Planned after substrate and off-state controls. |
|
||||
| Memory/continuity skill family | Deep-source grounded retained | skillization + memory doctrine | Retained, not implemented. |
|
||||
| Provider/ops skill family | Deep-source grounded retained | skillization + provider doctrine | Retained, not implemented. |
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ The landed bounded first-party `Phase S1-A` packet keeps:
|
|||
first-party
|
||||
- the landed bounded first-party `Phase S1-B` packet keeps durable master and
|
||||
per-skill off-state control first-party rather than hidden prompt babysitting
|
||||
- the landed bounded first-party `Phase S1-D` packet now keeps authoring
|
||||
template, registry-grounded examples, and smoke/eval validation structure
|
||||
first-party before wrappers land
|
||||
|
||||
## Memory-specific consequence
|
||||
|
||||
|
|
|
|||
|
|
@ -169,6 +169,10 @@ Canonical discovery surfaces for roadmap interpretation:
|
|||
control pass is now consumed
|
||||
- the bounded first-party `Phase S1-C` invocation/provenance/audit-ledger
|
||||
packet is now landed in current code
|
||||
- the generic first-party `Phase S1-D` authoring/examples/validation-harness
|
||||
control pass is now consumed
|
||||
- the bounded first-party `Phase S1-D` authoring/examples/validation-harness
|
||||
packet is now landed in current code
|
||||
- the generic source-backed `Phase 6R-R` shared classic-cube recognition multi-face
|
||||
correction/explanation control pass is now consumed
|
||||
- the bounded permissive `Phase 6R-R` shared classic-cube recognition multi-face
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ Includes:
|
|||
- command/service binding declarations
|
||||
- permission/scope declarations
|
||||
- provenance/log declarations
|
||||
- validation harness
|
||||
- still deferred:
|
||||
- authoring template expansion
|
||||
- example bundle
|
||||
- validation harness
|
||||
|
||||
### Analyzer and review skills
|
||||
|
||||
|
|
@ -130,9 +130,8 @@ A coding model working on HyperTwist should still be able to:
|
|||
|
||||
The next correct skillization sequence is:
|
||||
|
||||
1. authoring/examples/validation harness expansion
|
||||
2. permissive analyzer wrappers
|
||||
3. clean-room command-contract specs for restrictive lanes
|
||||
1. permissive analyzer wrappers
|
||||
2. clean-room command-contract specs for restrictive lanes
|
||||
|
||||
Broader memory, provider, and domain skill widening should wait until that
|
||||
base exists.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue