Compare commits

...
Author SHA1 Message Date
m 33365ce7ee GEN2-024: establish principal realms and source trust
CI / test (push) Failing after 26s
2026-08-29 11:57:19 +03:00
m 5017a854ee GEN2-023: make conversational configuration intent explicit
CI / test (push) Failing after 29s
2026-08-29 11:55:38 +03:00
m 839b35f310 GEN2 M4 remediation: durable recovery and governed evolution
CI / test (push) Failing after 26s
2026-08-29 11:47:05 +03:00
m 96687140ce GEN2-022: govern self evolution through development gates
CI / test (push) Failing after 27s
2026-08-29 11:31:45 +03:00
m b282038949 GEN2-021: add independent supervisor lifeboat
CI / test (push) Failing after 27s
2026-08-29 11:30:49 +03:00
m 4de506a2af GEN2-020: separate execution receipts from world outcomes
CI / test (push) Failing after 26s
2026-08-29 11:30:05 +03:00
m 36272b9036 GEN2-019: add advisory consequence assessment
CI / test (push) Failing after 29s
2026-08-29 11:28:52 +03:00
m a779568622 GEN2-018: add bounded perspectives over Work Graph
CI / test (push) Failing after 27s
2026-08-29 11:28:05 +03:00
m 243a11490b GEN2-017: add durable long-running investigations
CI / test (push) Failing after 26s
2026-08-29 11:27:21 +03:00
m 26207d93ef GEN2-016: add intelligence strategy and benchmark evidence
CI / test (push) Failing after 26s
2026-08-29 11:16:07 +03:00
m 42871f2e47 GEN2-015: add evidence-backed SELF ledger
CI / test (push) Failing after 28s
2026-08-29 11:13:38 +03:00
m 6ea1d4b729 GEN2-014: add reflex lifecycle and escalation
CI / test (push) Failing after 28s
2026-08-29 11:12:42 +03:00
m c6d1ebf36f GEN2-013: add versioned Skill V2 contracts
CI / test (push) Failing after 27s
2026-08-29 11:11:50 +03:00
m 25d8d6d219 GEN2-012: add typed scoped configuration
CI / test (push) Failing after 33s
2026-08-29 11:09:33 +03:00
m 6cbef9af41 GEN2-012: add scoped configuration bootstrap boundary
CI / test (push) Failing after 34s
2026-08-29 11:08:53 +03:00
m 2fe9802e5a GEN2-011: cut PersonalMemory to compatibility fallback
CI / test (push) Failing after 37s
2026-08-29 02:41:23 +03:00
m 0882df3ad2 GEN2-010: add bounded Context Compiler V2 trace
CI / test (push) Successful in 53s
2026-08-29 02:39:58 +03:00
m 0acbe53fad GEN2-009: add rebuildable retrieval projections
CI / test (push) Successful in 50s
2026-08-29 02:38:49 +03:00
m e634bb946a GEN2-008: promote experience and episode projections
CI / test (push) Successful in 55s
2026-08-29 02:37:28 +03:00
m c7ad996cae GEN2-007: add task-relative freshness assessment
CI / test (push) Successful in 52s
2026-08-29 02:35:54 +03:00
m a065382512 GEN2-006: normalize epistemic propositions and assessments
CI / test (push) Successful in 51s
2026-08-29 02:33:09 +03:00
m 8a8e571905 GEN2-005: govern identity resolution and version bindings
CI / test (push) Failing after 38s
2026-08-29 02:20:02 +03:00
m 301dbdcfb2 GEN2-004: add ContextScope and FocusStack V2
CI / test (push) Successful in 50s
2026-08-29 02:17:36 +03:00
m 8037e66998 GEN2-003: add typed World referent foundation
CI / test (push) Successful in 50s
2026-08-29 02:11:36 +03:00
m 29815c49b8 GEN2-002: add shared semantic primitives
CI / test (push) Successful in 52s
2026-08-29 02:08:20 +03:00
100 changed files with 3434 additions and 44 deletions
+33
View File
@@ -2,6 +2,7 @@ package postgres
import (
"context"
"encoding/json"
"strings"
"git.cin.su/m/Assistant/contracts/identity"
@@ -18,6 +19,38 @@ func OpenSituation(ctx context.Context, config ContinuityConfig) (*SituationRepo
}
return &SituationRepository{pool: pool}, nil
}
func (r *SituationRepository) SaveContextScope(ctx context.Context, scope situation.ContextScope) error {
if err := scope.Validate(); err != nil {
return err
}
bindings, err := json.Marshal(scope.Bindings)
if err != nil {
return err
}
_, err = r.pool.Exec(ctx, `INSERT INTO situation.context_scopes(context_scope_id,principal_id,revision,bindings,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5) ON CONFLICT(context_scope_id) DO UPDATE SET revision=EXCLUDED.revision, bindings=EXCLUDED.bindings, recorded_at_unix_millis=EXCLUDED.recorded_at_unix_millis`, scope.ID, scope.PrincipalID, scope.Revision, bindings, scope.RecordedAt)
return err
}
func (r *SituationRepository) SaveFocusFrame(ctx context.Context, frame situation.FocusFrame) error {
if err := frame.Validate(); err != nil {
return err
}
ref, err := json.Marshal(frame.ContextScopeRef)
if err != nil {
return err
}
_, err = r.pool.Exec(ctx, `INSERT INTO situation.focus_frames(focus_frame_id,principal_id,actor_id,revision,authority_scope_ref,context_scope_ref,goal_ref,task_ref,source_utterance_ref,provenance,confidence_millis,state,parent_frame_ref,activated_at_unix_millis,suspended_at_unix_millis,expired_at_unix_millis,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17) ON CONFLICT(focus_frame_id) DO UPDATE SET revision=EXCLUDED.revision, context_scope_ref=EXCLUDED.context_scope_ref, state=EXCLUDED.state, suspended_at_unix_millis=EXCLUDED.suspended_at_unix_millis, expired_at_unix_millis=EXCLUDED.expired_at_unix_millis, recorded_at_unix_millis=EXCLUDED.recorded_at_unix_millis`, frame.ID, frame.PrincipalID, frame.ActorID, frame.Revision, frame.AuthorityScopeRef, ref, frame.GoalRef, frame.TaskRef, frame.SourceUtteranceRef, frame.Provenance, frame.ConfidenceMillis, frame.State, frame.ParentFrameRef, frame.ActivatedAt, frame.SuspendedAt, frame.ExpiredAt, frame.RecordedAt)
return err
}
func (r *SituationRepository) AppendFocusTransition(ctx context.Context, transition situation.FocusTransition) error {
if err := transition.Validate(); err != nil {
return err
}
_, err := r.pool.Exec(ctx, `INSERT INTO situation.focus_transitions(transition_id,focus_frame_id,from_revision,to_revision,operation,cause_ref,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7)`, transition.TransitionID, transition.FrameID, transition.FromRevision, transition.ToRevision, transition.Operation, transition.CauseRef, transition.RecordedAt)
return err
}
func (r *SituationRepository) Close() { r.pool.Close() }
func (r *SituationRepository) Save(ctx context.Context, binding situation.FocusBinding) error {
_, err := r.pool.Exec(ctx, `INSERT INTO situation.focus_bindings (focus_binding_id, actor_id, session_id, workspace_id, project_id, goal_id, scope_id, active) VALUES ($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT (focus_binding_id) DO UPDATE SET active=EXCLUDED.active`, binding.ID, binding.ActorID, binding.SessionID, binding.Workspace, binding.ProjectID, binding.GoalID, binding.ScopeID, binding.Active)
+115
View File
@@ -25,6 +25,121 @@ var (
ErrDevelopmentCandidateConflict = errors.New("development candidate conflict")
)
func (r *WorkRepository) SaveInvestigation(ctx context.Context, value work.Investigation, expectedRevision int64) error {
if !value.Valid() || expectedRevision < 0 {
return errors.New("invalid investigation revision")
}
attempts := make([]string, 0, len(value.AttemptRefs))
for _, item := range value.AttemptRefs {
attempts = append(attempts, string(item))
}
hypotheses := make([]string, 0, len(value.HypothesisRefs))
for _, item := range value.HypothesisRefs {
hypotheses = append(hypotheses, string(item))
}
findings := make([]string, 0, len(value.FindingRefs))
for _, item := range value.FindingRefs {
findings = append(findings, string(item))
}
blockers := append([]string(nil), value.Blockers...)
checkpoints := make([]string, 0, len(value.CheckpointRefs))
for _, item := range value.CheckpointRefs {
checkpoints = append(checkpoints, string(item))
}
if expectedRevision == 0 {
result, err := r.pool.Exec(ctx, `INSERT INTO work.long_running_work(investigation_id,objective,hypothesis_refs,attempt_refs,finding_refs,blockers,checkpoint_refs,next_step,state,revision,time_budget_millis,cost_budget_micros,max_attempts,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) ON CONFLICT(investigation_id) DO NOTHING`, value.ID, value.Objective, hypotheses, attempts, findings, blockers, checkpoints, value.NextStep, value.State, value.Revision, value.TimeBudgetMillis, value.CostBudgetMicros, value.MaxAttempts, value.RecordedAtUnixMillis)
if err != nil {
return err
}
if result.RowsAffected() != 1 {
return errors.New("investigation already exists")
}
return nil
}
result, err := r.pool.Exec(ctx, `UPDATE work.long_running_work SET objective=$2,hypothesis_refs=$3,attempt_refs=$4,finding_refs=$5,blockers=$6,checkpoint_refs=$7,next_step=$8,state=$9,revision=$10,time_budget_millis=$11,cost_budget_micros=$12,max_attempts=$13,recorded_at_unix_millis=$14 WHERE investigation_id=$1 AND revision=$15`, value.ID, value.Objective, hypotheses, attempts, findings, blockers, checkpoints, value.NextStep, value.State, value.Revision, value.TimeBudgetMillis, value.CostBudgetMicros, value.MaxAttempts, value.RecordedAtUnixMillis, expectedRevision)
if err != nil {
return err
}
if result.RowsAffected() != 1 {
return errors.New("investigation revision conflict")
}
return nil
}
func (r *WorkRepository) LoadInvestigation(ctx context.Context, id work.LongRunningWorkID) (work.Investigation, error) {
var value work.Investigation
var hypotheses, attempts, findings, blockers, checkpoints []string
err := r.pool.QueryRow(ctx, `SELECT investigation_id,objective,hypothesis_refs,attempt_refs,finding_refs,blockers,checkpoint_refs,next_step,state,revision,time_budget_millis,cost_budget_micros,max_attempts,recorded_at_unix_millis FROM work.long_running_work WHERE investigation_id=$1`, id).Scan(&value.ID, &value.Objective, &hypotheses, &attempts, &findings, &blockers, &checkpoints, &value.NextStep, &value.State, &value.Revision, &value.TimeBudgetMillis, &value.CostBudgetMicros, &value.MaxAttempts, &value.RecordedAtUnixMillis)
if err != nil {
return work.Investigation{}, fmt.Errorf("load investigation: %w", err)
}
for _, item := range hypotheses {
value.HypothesisRefs = append(value.HypothesisRefs, work.EvidenceRef(item))
}
for _, item := range attempts {
value.AttemptRefs = append(value.AttemptRefs, work.AgentRunID(item))
}
for _, item := range findings {
value.FindingRefs = append(value.FindingRefs, work.EvidenceRef(item))
}
value.Blockers = append(value.Blockers, blockers...)
for _, item := range checkpoints {
value.CheckpointRefs = append(value.CheckpointRefs, work.AgentCheckpointID(item))
}
return value, nil
}
// SaveInvestigationCheckpoint atomically records the checkpoint and marks its
// attempts verified. The unique key makes retries idempotent.
func (r *WorkRepository) SaveInvestigationCheckpoint(ctx context.Context, checkpoint work.InvestigationCheckpoint) error {
if !checkpoint.Valid() {
return errors.New("invalid investigation checkpoint")
}
tx, err := r.pool.Begin(ctx)
if err != nil {
return err
}
defer tx.Rollback(ctx)
if _, err = tx.Exec(ctx, `INSERT INTO work.investigation_checkpoints(checkpoint_id,investigation_id,completed_attempt_refs,completed_finding_refs,next_step,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6) ON CONFLICT(checkpoint_id) DO NOTHING`, checkpoint.ID, checkpoint.InvestigationID, stringIDs(checkpoint.CompletedAttemptRefs), stringEvidence(checkpoint.CompletedFindingRefs), checkpoint.NextStep, checkpoint.RecordedAtUnixMillis); err != nil {
return err
}
for _, attempt := range checkpoint.CompletedAttemptRefs {
if _, err = tx.Exec(ctx, `INSERT INTO work.investigation_attempts(investigation_id,attempt_ref,verified_at_unix_millis) VALUES($1,$2,$3) ON CONFLICT(investigation_id,attempt_ref) DO NOTHING`, checkpoint.InvestigationID, attempt, checkpoint.RecordedAtUnixMillis); err != nil {
return err
}
}
return tx.Commit(ctx)
}
func (r *WorkRepository) UnverifiedInvestigationAttempts(ctx context.Context, id work.LongRunningWorkID, candidates []work.AgentRunID) ([]work.AgentRunID, error) {
result := make([]work.AgentRunID, 0, len(candidates))
for _, candidate := range candidates {
var exists bool
if err := r.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM work.investigation_attempts WHERE investigation_id=$1 AND attempt_ref=$2)`, id, candidate).Scan(&exists); err != nil {
return nil, err
}
if !exists {
result = append(result, candidate)
}
}
return result, nil
}
func stringIDs(values []work.AgentRunID) []string {
result := make([]string, 0, len(values))
for _, value := range values {
result = append(result, string(value))
}
return result
}
func stringEvidence(values []work.EvidenceRef) []string {
result := make([]string, 0, len(values))
for _, value := range values {
result = append(result, string(value))
}
return result
}
func OpenWork(ctx context.Context, config ContinuityConfig) (*WorkRepository, error) {
pool, err := openPool(ctx, config)
if err != nil {
+108
View File
@@ -0,0 +1,108 @@
package postgres
import (
"context"
"encoding/json"
"fmt"
"git.cin.su/m/Assistant/contracts/world"
worlddomain "git.cin.su/m/Assistant/modules/world/domain"
"github.com/jackc/pgx/v5/pgxpool"
)
type WorldRepository struct{ pool *pgxpool.Pool }
func OpenWorld(ctx context.Context, config ContinuityConfig) (*WorldRepository, error) {
pool, err := openPool(ctx, config)
if err != nil {
return nil, err
}
return &WorldRepository{pool: pool}, nil
}
func (r *WorldRepository) Close() { r.pool.Close() }
func (r *WorldRepository) SaveKindDefinition(ctx context.Context, value world.WorldObjectKindDefinition) error {
if err := worlddomain.ValidateKindDefinition(value); err != nil {
return err
}
var parentOwner, parentKind, parentID string
var parentRevision *uint64
if value.ParentKindRef != nil {
parentOwner, parentKind, parentID = value.ParentKindRef.OwnerNamespace, value.ParentKindRef.SemanticKind, string(value.ParentKindRef.StableID)
if value.ParentKindRef.Revision != nil {
revision := uint64(*value.ParentKindRef.Revision)
parentRevision = &revision
}
}
_, err := r.pool.Exec(ctx, `INSERT INTO world.kind_definitions(kind_definition_id,kind_key,revision,display_name,parent_owner_namespace,parent_semantic_kind,parent_stable_id,parent_revision,lifecycle,definition_digest,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11) ON CONFLICT(kind_definition_id) DO NOTHING`, value.ID, value.KindKey, value.Revision, value.DisplayName, parentOwner, parentKind, parentID, parentRevision, value.Lifecycle, value.DefinitionDigest, value.RecordedAt)
return err
}
func (r *WorldRepository) SaveObject(ctx context.Context, value world.WorldObject) error {
if err := worlddomain.ValidateObject(value); err != nil {
return err
}
_, err := r.pool.Exec(ctx, `INSERT INTO world.objects(world_object_id,principal_id,kind_owner_namespace,kind_semantic_kind,kind_stable_id,kind_revision,lifecycle,created_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT(world_object_id) DO NOTHING`, value.ID, value.PrincipalID, value.KindDefinitionRef.OwnerNamespace, value.KindDefinitionRef.SemanticKind, value.KindDefinitionRef.StableID, value.KindRevision, value.Lifecycle, value.CreatedAt)
return err
}
func (r *WorldRepository) SaveAlias(ctx context.Context, value world.WorldAlias) error {
if err := worlddomain.ValidateAlias(value); err != nil {
return err
}
_, err := r.pool.Exec(ctx, `INSERT INTO world.aliases(world_alias_id,principal_id,world_object_id,alias,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5) ON CONFLICT(world_alias_id) DO NOTHING`, value.ID, value.PrincipalID, value.ObjectID, value.Alias, value.RecordedAt)
return err
}
func (r *WorldRepository) SaveFacetDefinition(ctx context.Context, value world.FacetDefinition) error {
if err := worlddomain.ValidateFacetDefinition(value); err != nil {
return err
}
payload, err := json.Marshal(value.ValueType)
if err != nil {
return fmt.Errorf("encode facet value type: %w", err)
}
_, err = r.pool.Exec(ctx, `INSERT INTO world.facet_definitions(facet_definition_id,kind_key,revision,facet_key,value_type,definition_digest,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7) ON CONFLICT(facet_definition_id) DO NOTHING`, value.ID, value.KindKey, value.Revision, value.FacetKey, payload, value.DefinitionDigest, value.RecordedAt)
return err
}
func (r *WorldRepository) SaveRelationDefinition(ctx context.Context, value world.RelationDefinition) error {
if err := worlddomain.ValidateRelationDefinition(value); err != nil {
return err
}
_, err := r.pool.Exec(ctx, `INSERT INTO world.relation_definitions(relation_definition_id,kind_key,revision,relation_key,target_kind_key,definition_digest,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7) ON CONFLICT(relation_definition_id) DO NOTHING`, value.ID, value.KindKey, value.Revision, value.RelationKey, value.TargetKindKey, value.DefinitionDigest, value.RecordedAt)
return err
}
func (r *WorldRepository) SaveResolution(ctx context.Context, value world.IdentityResolutionDecisionRecord) error {
if err := worlddomain.ValidateResolution(value); err != nil {
return err
}
candidates, err := json.Marshal(value.Candidates)
if err != nil {
return fmt.Errorf("encode resolution candidates: %w", err)
}
evidence, err := json.Marshal(value.Evidence)
if err != nil {
return fmt.Errorf("encode resolution evidence: %w", err)
}
_, err = r.pool.Exec(ctx, `INSERT INTO world.identity_resolution_decisions(resolution_decision_id,principal_id,candidates,decision,evidence,confidence_millis,decided_at_unix_millis,revision) VALUES($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT(resolution_decision_id) DO NOTHING`, value.ID, value.PrincipalID, candidates, value.Decision, evidence, value.ConfidenceMillis, value.DecidedAt, value.Revision)
return err
}
func (r *WorldRepository) SaveLineage(ctx context.Context, value world.WorldLineage) error {
if err := worlddomain.ValidateLineage(value); err != nil {
return err
}
sources, err := json.Marshal(value.SourceRefs)
if err != nil {
return fmt.Errorf("encode lineage sources: %w", err)
}
successors, err := json.Marshal(value.SuccessorRefs)
if err != nil {
return fmt.Errorf("encode lineage successors: %w", err)
}
_, err = r.pool.Exec(ctx, `INSERT INTO world.lineage(lineage_id,operation,source_refs,successor_refs,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5) ON CONFLICT(lineage_id) DO NOTHING`, value.ID, value.Operation, sources, successors, value.RecordedAt)
return err
}
+4 -4
View File
@@ -533,7 +533,7 @@ func main() {
log.Printf("interaction principal history loaded: %d utterances", len(recentUserHistory))
}
conversationHistory = append(conversationHistory, recentUserHistory...)
personalMemory := interactiondomain.CompilePersonalMemory(conversationHistory)
gen2Context := interactiondomain.BuildGen2Context(conversationHistory)
if !creativeUserRequest && locationReply == "" {
if continuation := interactiondomain.ContinueLocalSearch(effectiveTaskMessage, conversationHistory); continuation != "" {
continuationMessage = continuation
@@ -829,7 +829,7 @@ func main() {
reply, backed := renderResearchReply(searchQuery, result, researchErr)
if !backed && cognitiveAvailable {
answerCtx, cancelAnswer := context.WithTimeout(r.Context(), 12*time.Second)
answer, answerErr := cognitiveClient.AnswerStableKnowledge(answerCtx, session, part, personalMemory.ContextText(), cognitive.TaskMeaning{
answer, answerErr := cognitiveClient.AnswerStableKnowledge(answerCtx, session, part, gen2Context.Text, cognitive.TaskMeaning{
SpeechAct: string(semantic.Interpretation.SpeechAct), CapabilityHints: toCapabilityKinds(semantic.CapabilityHints), RequestedOutcome: semantic.Interpretation.RequestedOutcome, InformationRequestKind: semantic.InformationRequestKind, ConfidenceMillis: semantic.Interpretation.ConfidenceMillis,
})
cancelAnswer()
@@ -869,7 +869,7 @@ func main() {
canGenerateTextReply := shouldGenerateNonMutatingTextDirective(semantic, routePlan, helpPath, creativeRequest) && planningReply == deterministicReply
if (planningReply == "" && needsCognition && semantic.Interpretation.SpeechAct == interaction.SpeechActQuestion || canGenerateTextReply) && !hasChatRoute(routePlan, chatRouteResearch) && !creativeRequest {
answerCtx, cancelAnswer := context.WithTimeout(r.Context(), 12*time.Second)
answer, answerErr := cognitiveClient.AnswerStableKnowledge(answerCtx, session, effectiveTaskMessage, personalMemory.ContextText(), cognitive.TaskMeaning{
answer, answerErr := cognitiveClient.AnswerStableKnowledge(answerCtx, session, effectiveTaskMessage, gen2Context.Text, cognitive.TaskMeaning{
SpeechAct: string(semantic.Interpretation.SpeechAct), CapabilityHints: toCapabilityKinds(semantic.CapabilityHints), RequestedOutcome: semantic.Interpretation.RequestedOutcome, InformationRequestKind: semantic.InformationRequestKind, ConfidenceMillis: semantic.Interpretation.ConfidenceMillis,
})
cancelAnswer()
@@ -992,7 +992,7 @@ func main() {
}
if strings.TrimSpace(planningReply) != "" {
reviewContext, cancelReview := context.WithTimeout(r.Context(), 12*time.Second)
reviewedReply, reviewErr := cognitiveClient.ReviewResponse(reviewContext, session, utterance.Content, planningReply, personalMemory.ContextText(), cognitive.TaskMeaning{
reviewedReply, reviewErr := cognitiveClient.ReviewResponse(reviewContext, session, utterance.Content, planningReply, gen2Context.Text, cognitive.TaskMeaning{
SpeechAct: string(semantic.Interpretation.SpeechAct),
CapabilityHints: toCapabilityKinds(semantic.CapabilityHints),
RequestedOutcome: semantic.Interpretation.RequestedOutcome,
+10
View File
@@ -0,0 +1,10 @@
package main
import "net/http"
func main() {
_ = http.ListenAndServe(":8088", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("lifeboat-ready\n"))
}))
}
+41
View File
@@ -0,0 +1,41 @@
package capability
type IntelligencePath string
const (
PathRule IntelligencePath = "RULE"
PathReflex IntelligencePath = "REFLEX"
PathSkill IntelligencePath = "SKILL"
PathSmallLocal IntelligencePath = "SMALL_LOCAL"
PathStrongLocal IntelligencePath = "STRONG_LOCAL"
PathExternal IntelligencePath = "EXTERNAL"
PathResearch IntelligencePath = "RESEARCH"
PathTeam IntelligencePath = "TEAM"
)
type StrategyRequest struct {
RequiredQuality int64
PreferLowLatency bool
CostBudgetMicros int64
RiskClass string
FreshnessRequired bool
CostOfError int64
}
type StrategyDecision struct {
Path IntelligencePath
Reason string
Escalate bool
}
func (r StrategyRequest) Select() StrategyDecision {
if r.RiskClass == "HIGH" || r.CostOfError >= 800 {
return StrategyDecision{Path: PathStrongLocal, Reason: "high consequence requires deeper reasoning", Escalate: true}
}
if r.RequiredQuality <= 500 && r.CostBudgetMicros > 0 {
return StrategyDecision{Path: PathRule, Reason: "bounded low-risk path"}
}
if r.PreferLowLatency {
return StrategyDecision{Path: PathReflex, Reason: "latency preference with later escalation"}
}
return StrategyDecision{Path: PathSkill, Reason: "validated reusable strategy"}
}
+61
View File
@@ -0,0 +1,61 @@
package capability
type ReflexID string
type ReflexLifecycle string
type ReflexKind string
const (
ReflexCandidate ReflexLifecycle = "CANDIDATE"
ReflexValidating ReflexLifecycle = "VALIDATING"
ReflexActive ReflexLifecycle = "ACTIVE"
ReflexDegraded ReflexLifecycle = "DEGRADED"
ReflexStale ReflexLifecycle = "STALE"
ReflexSuspended ReflexLifecycle = "SUSPENDED"
ReflexRetired ReflexLifecycle = "RETIRED"
ReflexDeterministicCode ReflexKind = "DETERMINISTIC_CODE"
ReflexRule ReflexKind = "RULE"
ReflexWorkflow ReflexKind = "WORKFLOW"
ReflexQueryTemplate ReflexKind = "QUERY_TEMPLATE"
ReflexSmallModelChain ReflexKind = "SMALL_MODEL_CHAIN"
ReflexBoundedAdapter ReflexKind = "BOUNDED_ADAPTER_OPERATION"
)
type ShadowPolicy struct {
Enabled bool
SampleRateMillis int64
ComparatorRef string
MaxShadowCostMicros *int64
EligibleErrorCostClasses []string
}
type RevalidationPolicy struct {
MaxAgeMillis *int64
RevalidateOnDependencyRevisionChange bool
RevalidateOnWorldVersionChange bool
RevalidateAfterFailureCount *int64
RevalidateAfterCorrectionCount *int64
SampleAuditRateMillis *int64
}
type Reflex struct {
ID ReflexID
PrincipalID string
SourceSkillRef SkillID
CreatedAt int64
}
type ReflexRevision struct {
ReflexID ReflexID
Revision int64
SourceSkillRevision int64
Kind ReflexKind
Applicability ApplicabilitySpec
ImplementationRef string
ImplementationVersion string
ArtifactDigest string
DependencyRefs []string
ValidationEvidenceRefs []SkillEvidenceRef
KnownFailureExperienceRefs []SkillEvidenceRef
Shadow ShadowPolicy
Revalidation RevalidationPolicy
LastValidatedAt int64
Lifecycle ReflexLifecycle
RecordedAt int64
}
+36
View File
@@ -0,0 +1,36 @@
package capability
type SkillID string
type SkillRevision struct {
SkillID SkillID
Revision int64
Description string
Applicability ApplicabilitySpec
ImplementationRef string
ImplementationVersion string
DependencyRefs []string
SupportingExperienceRefs []SkillEvidenceRef
KnownFailureExperienceRefs []SkillEvidenceRef
ValidationEvidenceRefs []SkillEvidenceRef
QualityAssessmentRefs []string
EnvironmentVersionConstraints []string
LastValidatedAt int64
Lifecycle SkillLifecycleStatus
SupersedesRevision int64
RecordedAt int64
}
type ApplicabilitySpec struct {
RequiredContextBindings []string
PreferredContextBindings []string
ExcludedContextBindings []string
RequiredWorldKinds []string
VersionConstraints []string
InputConditions []string
MinimumEvidenceFreshness string
}
type Skill struct {
ID SkillID
PrincipalID string
Name string
CreatedAt int64
}
+41 -5
View File
@@ -11,14 +11,24 @@ import (
var ErrInvalidContextBudget = errors.New("context budget must be positive")
type ContextCandidate struct {
Excerpt ContextExcerpt
Relevance int
Excerpt ContextExcerpt
Relevance int
Lane string
ContextScopeRef string
FreshnessState string
Negative bool
}
type ContextCompileInput struct {
Candidates []ContextCandidate
DataPolicy capability.DataPolicy
MaxBytes int
Candidates []ContextCandidate
DataPolicy capability.DataPolicy
MaxBytes int
TaskRef string
FocusFrameRef string
ContextScopeRef string
FreshnessRequirement string
RiskClass string
TokenBudget int
}
type ContextOmission struct {
@@ -30,6 +40,24 @@ type ContextBundle struct {
Excerpts []ContextExcerpt
Omissions []ContextOmission
Bytes int
Trace ContextAssemblyTrace
}
type ContextAssemblyTrace struct {
Included []ContextExcerptID
Excluded []ContextOmission
Coverage string
CompilerVersion string
}
type IterativeRetrievalRequest struct {
Query string
RemainingBytes int
Pass int
}
type IterativeRetrievalResponse struct {
Candidates []ContextCandidate
Exhausted bool
}
// CompileContext deterministically selects permitted, relevant excerpts for a
@@ -54,6 +82,10 @@ func CompileContext(input ContextCompileInput) (ContextBundle, error) {
continue
}
seen[excerpt.ID] = struct{}{}
if input.ContextScopeRef != "" && candidate.ContextScopeRef != input.ContextScopeRef {
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: "context_scope"})
continue
}
reason := permittedContextReason(excerpt, input.DataPolicy)
if reason != "" {
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: reason})
@@ -70,7 +102,11 @@ func CompileContext(input ContextCompileInput) (ContextBundle, error) {
}
bundle.Excerpts = append(bundle.Excerpts, excerpt)
bundle.Bytes += bytes
bundle.Trace.Included = append(bundle.Trace.Included, excerpt.ID)
}
bundle.Trace.Excluded = append([]ContextOmission(nil), bundle.Omissions...)
bundle.Trace.CompilerVersion = "context-compiler-v2-additive"
bundle.Trace.Coverage = "BOUNDED"
return bundle, nil
}
@@ -0,0 +1,14 @@
package cognitive_test
import (
"git.cin.su/m/Assistant/contracts/capability"
"git.cin.su/m/Assistant/contracts/cognitive"
"testing"
)
func TestContextCompilerV2TraceAndBudgetRemainDeterministic(t *testing.T) {
b, err := cognitive.CompileContext(cognitive.ContextCompileInput{MaxBytes: 5, DataPolicy: capability.DataPolicyLocalOnly, TaskRef: "task", FocusFrameRef: "frame", ContextScopeRef: "company-a", Candidates: []cognitive.ContextCandidate{{Excerpt: cognitive.ContextExcerpt{ID: "a", Text: "123", Sensitivity: cognitive.SensitivityPrivateAllowed}, ContextScopeRef: "company-a", Relevance: 10}, {Excerpt: cognitive.ContextExcerpt{ID: "b", Text: "123456", Sensitivity: cognitive.SensitivityPrivateAllowed}, ContextScopeRef: "company-b", Relevance: 100}}})
if err != nil || len(b.Excerpts) != 1 || len(b.Trace.Excluded) != 1 {
t.Fatalf("bundle=%#v err=%v", b, err)
}
}
+32
View File
@@ -0,0 +1,32 @@
package commit
type ExecutorResult string
type AmbiguityState string
const (
ExecutorAccepted ExecutorResult = "ACCEPTED"
ExecutorReportedSuccess ExecutorResult = "REPORTED_SUCCESS"
ExecutorReportedFailure ExecutorResult = "REPORTED_FAILURE"
ExecutorNoResponse ExecutorResult = "NO_RESPONSE"
ExecutorAmbiguous ExecutorResult = "AMBIGUOUS"
)
type ExecutionReceipt struct {
ID string
ActionAttemptRef ActionAttemptID
ExecutorImplementationRef string
ExternalOperationRef string
ExternalRequestID string
RequestDigest string
ResponseDigest string
DispatchAtUnixMillis int64
CompletedAtUnixMillis *int64
ExecutorResult ExecutorResult
Ambiguity AmbiguityState
ReconciliationKey string
RawArtifactRef string
}
func (r ExecutionReceipt) Valid() bool {
return r.ID != "" && r.ActionAttemptRef != "" && r.ExecutorImplementationRef != "" && r.RequestDigest != "" && r.ExecutorResult != "" && r.ReconciliationKey != "" && r.DispatchAtUnixMillis > 0
}
+7
View File
@@ -0,0 +1,7 @@
package configuration
import "git.cin.su/m/Assistant/platform/ids"
// SemanticReference is a typed cross-owner reference; settings remain
// Configuration-owned records.
type SemanticReference = ids.SemanticRef
+101
View File
@@ -0,0 +1,101 @@
package configuration
import (
"fmt"
"git.cin.su/m/Assistant/contracts/secrets"
"git.cin.su/m/Assistant/platform/ids"
)
type SettingDefinitionID ids.StableID
type SettingAssignmentID ids.StableID
type ConfigurationRevision ids.Revision
type ValueType string
type ResolutionMode string
type SettingLifecycle string
type SettingSource string
const (
ValueString ValueType = "STRING"
ValueInteger ValueType = "INTEGER"
ValueBoolean ValueType = "BOOLEAN"
ValueSecretRef ValueType = "SECRET_REF"
ResolutionMostSpecific ResolutionMode = "MOST_SPECIFIC_WINS"
ResolutionFirstHuman ResolutionMode = "FIRST_EXPLICIT_HUMAN_WINS"
ResolutionMergeList ResolutionMode = "MERGE_LIST"
SettingActive SettingLifecycle = "ACTIVE"
SettingDeprecated SettingLifecycle = "DEPRECATED"
SettingRetired SettingLifecycle = "RETIRED"
SourceHumanDirective SettingSource = "HUMAN_DIRECTIVE"
SourceMigrated SettingSource = "MIGRATED_CONFIG"
SourceSkillDefault SettingSource = "SKILL_DEFAULT"
SourceSystemDefault SettingSource = "SYSTEM_DEFAULT"
SourceGovernedChange SettingSource = "GOVERNED_CHANGE"
)
type SettingDefinition struct {
ID SettingDefinitionID
OwnerNamespace string
StableKey string
Revision ConfigurationRevision
ValueType ValueType
DefaultValue string
Sensitivity string
Lifecycle SettingLifecycle
RecordedAtUnixMillis int64
}
type ScopeSelector struct {
PrincipalRef string
RequiredContextBindings []string
ActivityRef string
SkillRef string
TaskRef string
SessionRef string
TemporaryOverride bool
}
type SettingAssignment struct {
ID SettingAssignmentID
PrincipalID string
DefinitionRef string
DefinitionRevision ConfigurationRevision
Revision ConfigurationRevision
Selector ScopeSelector
TypedValue string
SecretRef *secrets.CredentialRef
EffectiveFromUnixMillis int64
EffectiveUntilUnixMillis *int64
Source SettingSource
SourceRef string
Lifecycle SettingLifecycle
RecordedAtUnixMillis int64
}
type EffectiveSetting struct {
DefinitionRef string
Value string
WinningAssignmentRef string
ResolutionTrace []string
}
type BootstrapConfig struct {
NodeIdentity string
ControlDatabaseLocator string
RootSecretResolverLocator string
RecoveryLocator string
}
// ConversationalConfigurationCommand is an intent, not an assignment. Only
// Configuration may turn a SET command into durable state.
func (d SettingDefinition) Validate() error {
if d.ID == "" || d.OwnerNamespace == "" || d.StableKey == "" || !ids.Revision(d.Revision).Valid() || d.ValueType == "" || d.Lifecycle == "" || d.RecordedAtUnixMillis < 1 {
return fmt.Errorf("invalid setting definition")
}
return nil
}
func (a SettingAssignment) Validate() error {
if a.ID == "" || a.PrincipalID == "" || a.DefinitionRef == "" || !ids.Revision(a.Revision).Valid() || a.Source == "" || a.Lifecycle == "" || a.RecordedAtUnixMillis < 1 {
return fmt.Errorf("invalid setting assignment")
}
if a.SecretRef != nil && a.TypedValue != "" {
return fmt.Errorf("secret assignment must not contain typed value")
}
return nil
}
+90
View File
@@ -0,0 +1,90 @@
package epistemics
import (
"fmt"
"git.cin.su/m/Assistant/contracts/world"
)
type VolatilityMode string
const (
VolatilityImmutable VolatilityMode = "IMMUTABLE"
VolatilityVersionBound VolatilityMode = "VERSION_BOUND"
VolatilityVerySlow VolatilityMode = "VERY_SLOW"
VolatilitySlow VolatilityMode = "SLOW"
VolatilityMedium VolatilityMode = "MEDIUM"
VolatilityFast VolatilityMode = "FAST"
VolatilityEphemeral VolatilityMode = "EPHEMERAL"
VolatilityCustom VolatilityMode = "CUSTOM"
)
type TemporalApplicability struct {
ObservedAtUnixMillis int64
ValidFromUnixMillis *int64
ValidUntilUnixMillis *int64
LastVerifiedAtUnixMillis *int64
Volatility VolatilitySpec
VersionBindings []world.VersionBinding
}
type VolatilitySpec struct {
Mode VolatilityMode
ExpectedChangeIntervalMillis *int64
RevalidateAfterMillis *int64
HardStaleAfterMillis *int64
InvalidateOnVersionChange bool
RevalidationPolicyRef string
}
type FreshnessAssessmentState string
const (
FreshnessAssessmentCurrent FreshnessAssessmentState = "CURRENT"
FreshnessAssessmentAcceptable FreshnessAssessmentState = "ACCEPTABLE"
FreshnessAssessmentAging FreshnessAssessmentState = "AGING"
FreshnessAssessmentStale FreshnessAssessmentState = "STALE"
FreshnessAssessmentVersionMismatch FreshnessAssessmentState = "VERSION_MISMATCH"
FreshnessAssessmentHistoricalOnly FreshnessAssessmentState = "HISTORICAL_ONLY"
FreshnessAssessmentUnknown FreshnessAssessmentState = "UNKNOWN"
)
type FreshnessAssessment struct {
SourceKnowledgeRef string
TaskRef string
State FreshnessAssessmentState
Reason string
AgeMillis int64
VersionMatchState string
RevalidationAttemptRef string
AssessedAtUnixMillis int64
}
type RevalidationRequest struct {
ID string
SourceKnowledgeRef string
TaskRef string
RequiredVersionRefs []world.SemanticReference
RequestedAtUnixMillis int64
}
type RevalidationResponse struct {
RequestID string
Assessment FreshnessAssessment
NewEvidenceRefs []EvidenceRef
CompletedAtUnixMillis int64
}
func (v VolatilitySpec) Validate() error {
if v.Mode == "" {
return fmt.Errorf("volatility mode is required")
}
return nil
}
func (t TemporalApplicability) Validate() error {
if t.ObservedAtUnixMillis < 1 {
return fmt.Errorf("observed time is required")
}
return t.Volatility.Validate()
}
func (a FreshnessAssessment) Validate() error {
if a.SourceKnowledgeRef == "" || a.TaskRef == "" || a.State == "" || a.AgeMillis < 0 || a.AssessedAtUnixMillis < 1 {
return fmt.Errorf("freshness assessment is incomplete")
}
return nil
}
+30
View File
@@ -0,0 +1,30 @@
package epistemics
type WorldOutcomeState string
const (
OutcomeVerifiedSuccess WorldOutcomeState = "VERIFIED_SUCCESS"
OutcomeVerifiedPartial WorldOutcomeState = "VERIFIED_PARTIAL"
OutcomeVerifiedFailure WorldOutcomeState = "VERIFIED_FAILURE"
OutcomeUnverified WorldOutcomeState = "UNVERIFIED"
OutcomeUnknownState WorldOutcomeState = "UNKNOWN"
OutcomeConflicted WorldOutcomeState = "CONFLICTED"
)
type WorldOutcomeAssessment struct {
ID string
PrincipalID string
ActionAttemptRef string
ExecutionReceiptRefs []string
ExpectedEffectRef string
ObservationRefs []ObservationID
ClaimRefs []ClaimID
State WorldOutcomeState
ConfidenceMillis int64
EvidenceRefs []EvidenceRef
AssessedAt int64
}
func (a WorldOutcomeAssessment) Valid() bool {
return a.ID != "" && a.PrincipalID != "" && a.ActionAttemptRef != "" && a.State != "" && a.ConfidenceMillis >= 0 && a.ConfidenceMillis <= 1000 && a.AssessedAt > 0
}
+7
View File
@@ -0,0 +1,7 @@
package epistemics
import "git.cin.su/m/Assistant/platform/ids"
// SemanticReference identifies evidence-related records without transferring
// canonical ownership to Epistemics.
type SemanticReference = ids.SemanticRef
+34 -15
View File
@@ -17,23 +17,27 @@ type CoverageState string
type ConflictState string
type EvidenceKind string
type ResearchFindingState string
type ReliabilityState string
const (
FreshnessCurrent FreshnessState = "CURRENT"
FreshnessStale FreshnessState = "STALE"
FreshnessUnknown FreshnessState = "UNKNOWN"
CoverageComplete CoverageState = "COMPLETE"
CoveragePartial CoverageState = "PARTIAL"
CoverageUnknown CoverageState = "UNKNOWN"
ConflictNone ConflictState = "NONE"
ConflictPresent ConflictState = "PRESENT"
ConflictUnknown ConflictState = "UNKNOWN"
EvidenceObserved EvidenceKind = "OBSERVED"
EvidenceAssumed EvidenceKind = "ASSUMED"
FindingSupported ResearchFindingState = "SUPPORTED"
FindingStale ResearchFindingState = "STALE"
FindingConflicted ResearchFindingState = "CONFLICTED"
FindingUnknown ResearchFindingState = "UNKNOWN"
FreshnessCurrent FreshnessState = "CURRENT"
FreshnessStale FreshnessState = "STALE"
FreshnessUnknown FreshnessState = "UNKNOWN"
CoverageComplete CoverageState = "COMPLETE"
CoveragePartial CoverageState = "PARTIAL"
CoverageUnknown CoverageState = "UNKNOWN"
ConflictNone ConflictState = "NONE"
ConflictPresent ConflictState = "PRESENT"
ConflictUnknown ConflictState = "UNKNOWN"
EvidenceObserved EvidenceKind = "OBSERVED"
EvidenceAssumed EvidenceKind = "ASSUMED"
FindingSupported ResearchFindingState = "SUPPORTED"
FindingStale ResearchFindingState = "STALE"
FindingConflicted ResearchFindingState = "CONFLICTED"
FindingUnknown ResearchFindingState = "UNKNOWN"
ReliabilityCurrent ReliabilityState = "CURRENT"
ReliabilityAging ReliabilityState = "AGING"
ReliabilityUnknown ReliabilityState = "UNKNOWN"
)
type ResearchPlan struct {
@@ -52,6 +56,21 @@ type Source struct {
Publisher string
}
type SourceReliabilityAssessment struct {
SourceRef string
DomainRef string
Freshness FreshnessState
HistoryScoreMillis int64
ReliabilityScoreMillis int64
State ReliabilityState
EvidenceRefs []string
AssessedAtUnixMillis int64
}
func (a SourceReliabilityAssessment) Valid() bool {
return a.SourceRef != "" && a.DomainRef != "" && a.Freshness != "" && a.HistoryScoreMillis >= 0 && a.HistoryScoreMillis <= 1000 && a.ReliabilityScoreMillis >= 0 && a.ReliabilityScoreMillis <= 1000 && a.State != "" && a.AssessedAtUnixMillis > 0
}
type SourceSnapshot struct {
ID SourceSnapshotID
SourceID SourceID
+20 -10
View File
@@ -1,5 +1,7 @@
package epistemics
import "git.cin.su/m/Assistant/platform/ids"
type BeliefState string
const (
@@ -9,19 +11,27 @@ const (
)
type Observation struct {
ID ObservationID
SourceSnapshot SourceSnapshotID
Excerpt SourceExcerptID
Text string
ObservedAt int64
ID ObservationID
SourceSnapshot SourceSnapshotID
Excerpt SourceExcerptID
Text string
ObservedAt int64
PrincipalID string
ContextScopeRef string
ObservationKind string
Payload string
ExtractorRef string
}
type Claim struct {
ID ClaimID
Statement string
ObservationID ObservationID
CitationID CitationID
Verification VerificationState
ID ClaimID
Statement string
ObservationID ObservationID
CitationID CitationID
Verification VerificationState
PropositionID ids.ID
RevisedFrom *ClaimID
RecordedAtUnixMillis int64
}
type Belief struct {
+48
View File
@@ -24,6 +24,8 @@ type HelpMethodKind string
type OutcomeClass string
type ReflectionTriggerKind string
type ReflectionCandidateState string
type PropositionKind string
type BeliefAssessmentState string
const (
VerificationUnverified VerificationState = "UNVERIFIED"
@@ -73,6 +75,12 @@ const (
ReflectionCandidateEvaluating ReflectionCandidateState = "EVALUATING"
ReflectionCandidateSuperseded ReflectionCandidateState = "SUPERSEDED"
ReflectionCandidateResolved ReflectionCandidateState = "RESOLVED"
PropositionWorldFacet PropositionKind = "WORLD_FACET"
PropositionWorldRelation PropositionKind = "WORLD_RELATION"
PropositionOwnerDefined PropositionKind = "OWNER_DEFINED"
PropositionTextual PropositionKind = "TEXTUAL"
BeliefAssessmentCurrent BeliefAssessmentState = "CURRENT"
BeliefAssessmentSuperseded BeliefAssessmentState = "SUPERSEDED"
)
// SystemExpectation records what Domovoy expected a meaningful help path to
@@ -114,6 +122,15 @@ type ExperienceRecord struct {
VerificationEvidence []EvidenceRef
ConfidenceMillis int64
RecordedAtUnixMillis int64
ProblemStatement string
AttemptRef string
WhyAttempted string
ApplicabilityConditions []string
ContextScopeRef string
EpisodeRef string
GoalRef string
TaskRef string
WhySucceededOrFailed string
}
// ReflectionCandidate records that broader reflection may be warranted.
@@ -134,3 +151,34 @@ type ReflectionCandidate struct {
ClaimedBy string
ClaimExpiresAtUnixMillis int64
}
type Proposition struct {
ID ids.ID
Kind PropositionKind
SubjectRef string
PredicateRef string
ObjectValue string
ObjectRef string
Qualifiers []string
TextFallback string
}
type BeliefAssessment struct {
ID ids.ID
ClaimID ClaimID
Revision ids.Revision
State BeliefAssessmentState
ConfidenceMillis int64
EvidenceRefs []EvidenceRef
AssessedAtUnixMillis int64
}
type EpisodeID ids.ID
type Episode struct {
ID EpisodeID
PrincipalID string
ExperienceRefs []ExperienceRecordID
Summary string
Outcome OutcomeClass
RecordedAtUnixMillis int64
}
+24
View File
@@ -6,6 +6,30 @@ type ActorID ids.ID
type PrincipalID ids.ID
type IdentityID ids.ID
type DataRealmKind string
const (
DataRealmPersonal DataRealmKind = "PERSONAL"
DataRealmShared DataRealmKind = "SHARED"
DataRealmPublic DataRealmKind = "PUBLIC"
)
// PrincipalDataRealm is an identity-owned access boundary. It does not make
// a speaker or World person referent an authenticated principal.
type PrincipalDataRealm struct {
ID string
OwnerPrincipalID PrincipalID
Kind DataRealmKind
MemberPrincipalIDs []PrincipalID
Shared bool
Revision int64
RecordedAtUnixMillis int64
}
func (r PrincipalDataRealm) Valid() bool {
return r.ID != "" && r.OwnerPrincipalID != "" && (r.Kind == DataRealmPersonal || r.Kind == DataRealmShared || r.Kind == DataRealmPublic) && r.Revision > 0 && r.RecordedAtUnixMillis > 0 && (r.Kind != DataRealmShared || r.Shared)
}
// PrincipalBinding keeps the operational actor separate from the interest on
// whose behalf it acts. A Creator is not exempt from this distinction.
type PrincipalBinding struct {
+22
View File
@@ -25,6 +25,14 @@ type SemanticApplicability string
type SemanticCandidateSource string
type SemanticCandidateSelectionState string
type InformationRequestKind string
type ConfigurationCommandKind string
type SpeakerAttribution struct {
SourceRef string
PrincipalCandidate string
ConfidenceMillis int64
Authenticated bool
ObservationRef string
}
const (
ChannelWebChat Channel = "WEB_CHAT"
@@ -75,6 +83,8 @@ const (
InformationRequestMemoryInventory InformationRequestKind = "MEMORY_INVENTORY"
InformationRequestTimeDifference InformationRequestKind = "TIME_DIFFERENCE"
InformationRequestResearchFailureExplanation InformationRequestKind = "RESEARCH_FAILURE_EXPLANATION"
ConfigurationCommandSet ConfigurationCommandKind = "SET"
ConfigurationCommandQuery ConfigurationCommandKind = "QUERY"
)
type Conversation struct {
@@ -106,6 +116,18 @@ type OriginalHumanIntent struct {
RecordedAtUnixMillis int64
Text string
}
// ConfigurationCommand is Interaction-owned intent. Configuration remains
// the only owner allowed to materialise a SettingAssignment.
type ConfigurationCommand struct {
Kind ConfigurationCommandKind
PrincipalID string
DefinitionRef string
TypedValue string
TemporaryOverride bool
SessionRef string
SourceRef string
}
type InteractionRelation struct {
ID InteractionRelationID
FromUtteranceID HumanUtteranceID
+25
View File
@@ -0,0 +1,25 @@
package self
type BenchmarkCaseRef string
type PersonalBenchmark struct {
ID string
PrincipalID string
ApprovedCaseRefs []BenchmarkCaseRef
GoalProfile []string
PreferenceEvidenceRefs []SemanticReference
RecordedAt int64
}
type BenchmarkEvaluation struct {
CaseRef BenchmarkCaseRef
Path string
QualityMillis int64
ReliabilityMillis int64
LatencyMillis int64
CostMicros int64
CorrectionCount int64
EvidenceRefs []SemanticReference
}
func (e BenchmarkEvaluation) Valid() bool {
return e.CaseRef != "" && len(e.EvidenceRefs) > 0 && e.QualityMillis >= 0 && e.ReliabilityMillis >= 0 && e.CorrectionCount >= 0
}
+7
View File
@@ -0,0 +1,7 @@
package self
import "git.cin.su/m/Assistant/platform/ids"
// SemanticReference lets SELF cite evidence and capabilities without owning
// their canonical state.
type SemanticReference = ids.SemanticRef
+92
View File
@@ -0,0 +1,92 @@
package self
import "fmt"
type AssessmentID string
type LearningLedgerEntryID string
type AssessmentState string
const (
AssessmentCandidate AssessmentState = "CANDIDATE"
AssessmentConfirmed AssessmentState = "CONFIRMED"
AssessmentMonitoring AssessmentState = "MONITORING"
AssessmentResolved AssessmentState = "RESOLVED"
)
type CompetenceAssessment struct {
ID AssessmentID
PrincipalID string
SubjectRef SemanticReference
Revision uint64
ContextMatcher []string
QualityMillis int64
ReliabilityMillis int64
ConfidenceMillis int64
EvidenceRefs []SemanticReference
LastValidatedAt int64
AssessedAt int64
SupersedesRef *SemanticReference
}
type WeaknessPattern struct {
ID AssessmentID
PrincipalID string
Revision uint64
PatternKey string
ContextMatcher []string
FailureMode string
DetectionEvidenceRefs []SemanticReference
State AssessmentState
RecordedAt int64
}
type DependencyAssessment struct {
ID AssessmentID
SubjectRef SemanticReference
DependencyRef SemanticReference
ImpactClass string
CurrentEffect string
EvidenceRefs []SemanticReference
AssessedAt int64
}
type ImprovementNeed struct {
ID AssessmentID
PrincipalID string
SubjectRef SemanticReference
ProblemSummary string
EvidenceRefs []SemanticReference
ExpectedBenefit string
Priority int
State string
CreatedAt int64
}
type LearningLedgerEntry struct {
ID LearningLedgerEntryID
PrincipalID string
ImprovementNeedRef *SemanticReference
ObservedProblem string
EvidenceRefs []SemanticReference
Diagnosis string
Hypothesis string
ProposedChangeRef SemanticReference
ExpectedImprovement string
ActualEvaluationRefs []SemanticReference
DevelopmentGateRef *SemanticReference
BeforeVersionRefs []SemanticReference
AfterVersionRefs []SemanticReference
Decision string
SideEffects []string
RollbackRef *SemanticReference
RecordedAt int64
}
func (a CompetenceAssessment) Validate() error {
if a.ID == "" || a.PrincipalID == "" || !a.SubjectRef.Valid() || a.Revision < 1 || a.ConfidenceMillis < 0 || a.ConfidenceMillis > 1000 || len(a.EvidenceRefs) == 0 || a.AssessedAt < 1 {
return fmt.Errorf("competence requires evidence")
}
return nil
}
func (l LearningLedgerEntry) Validate() error {
if l.ID == "" || l.PrincipalID == "" || l.ObservedProblem == "" || len(l.EvidenceRefs) == 0 || l.Decision == "" || l.RecordedAt < 1 {
return fmt.Errorf("learning ledger entry is incomplete")
}
return nil
}
+141
View File
@@ -0,0 +1,141 @@
package situation
import (
"fmt"
"git.cin.su/m/Assistant/contracts/authority"
"git.cin.su/m/Assistant/contracts/identity"
"git.cin.su/m/Assistant/contracts/work"
"git.cin.su/m/Assistant/platform/clock"
"git.cin.su/m/Assistant/platform/ids"
)
type ContextScopeID ids.StableID
type FocusFrameID ids.StableID
type FocusTransitionID ids.StableID
type FocusRevision ids.Revision
type RoleKey string
type MatchPolicy string
type FocusFrameState string
type FocusProvenance string
type FocusTransitionOperation string
const (
MatchRequired MatchPolicy = "REQUIRED"
MatchPreferred MatchPolicy = "PREFERRED"
MatchRelated MatchPolicy = "RELATED"
MatchExcluded MatchPolicy = "EXCLUDED"
RolePerson RoleKey = "PERSON"
RoleOrganization RoleKey = "ORGANIZATION"
RoleFamily RoleKey = "FAMILY"
RoleEnvironment RoleKey = "ENVIRONMENT"
RoleLocation RoleKey = "LOCATION"
RoleSystem RoleKey = "SYSTEM"
RoleDatabase RoleKey = "DATABASE"
RoleRepository RoleKey = "REPOSITORY"
RoleBranch RoleKey = "BRANCH"
RoleVersion RoleKey = "VERSION"
RoleActivity RoleKey = "ACTIVITY"
RoleProject RoleKey = "PROJECT"
RoleActiveEntity RoleKey = "ACTIVE_ENTITY"
FocusCandidate FocusFrameState = "CANDIDATE"
FocusActive FocusFrameState = "ACTIVE"
FocusSuspended FocusFrameState = "SUSPENDED"
FocusExpired FocusFrameState = "EXPIRED"
FocusSuperseded FocusFrameState = "SUPERSEDED"
FocusExplicitHuman FocusProvenance = "EXPLICIT_HUMAN"
FocusUserConfirmed FocusProvenance = "USER_CONFIRMED"
FocusInherited FocusProvenance = "INHERITED"
FocusEntityReference FocusProvenance = "ENTITY_REFERENCE"
FocusTaskReference FocusProvenance = "TASK_REFERENCE"
FocusRepositoryReference FocusProvenance = "REPOSITORY_REFERENCE"
FocusEnvironmentObservation FocusProvenance = "ENVIRONMENT_OBSERVATION"
FocusInferred FocusProvenance = "INFERRED"
TransitionActivate FocusTransitionOperation = "ACTIVATE"
TransitionSuspend FocusTransitionOperation = "SUSPEND"
TransitionResume FocusTransitionOperation = "RESUME"
TransitionSupersede FocusTransitionOperation = "SUPERSEDE"
TransitionExpire FocusTransitionOperation = "EXPIRE"
)
type ContextBinding struct {
RoleKey RoleKey
TargetRef SemanticReference
MatchPolicy MatchPolicy
Provenance string
ConfidenceMillis int64
SourceRef *SemanticReference
}
type ContextScope struct {
ID ContextScopeID
PrincipalID identity.PrincipalID
Revision FocusRevision
Bindings []ContextBinding
RecordedAt clock.Instant
}
type FocusFrame struct {
ID FocusFrameID
PrincipalID identity.PrincipalID
ActorID identity.ActorID
Revision FocusRevision
AuthorityScopeRef authority.ScopeID
ContextScopeRef SemanticReference
GoalRef *work.GoalID
TaskRef *work.TaskID
SourceUtteranceRef string
Provenance FocusProvenance
ConfidenceMillis int64
State FocusFrameState
ParentFrameRef *FocusFrameID
ActivatedAt clock.Instant
SuspendedAt *clock.Instant
ExpiredAt *clock.Instant
RecordedAt clock.Instant
}
type FocusTransition struct {
TransitionID FocusTransitionID
FrameID FocusFrameID
FromRevision FocusRevision
ToRevision FocusRevision
Operation FocusTransitionOperation
CauseRef string
RecordedAt clock.Instant
}
func (s ContextScope) Validate() error {
if s.ID == "" || s.PrincipalID == "" || !ids.Revision(s.Revision).Valid() || !s.RecordedAt.Valid() {
return fmt.Errorf("invalid context scope")
}
for _, b := range s.Bindings {
if b.RoleKey == "" || !b.TargetRef.Valid() || !validMatchPolicy(b.MatchPolicy) {
return fmt.Errorf("invalid context binding")
}
}
return nil
}
func (f FocusFrame) Validate() error {
if f.ID == "" || f.PrincipalID == "" || f.ActorID == "" || !ids.Revision(f.Revision).Valid() || !f.ContextScopeRef.Valid() || f.State == "" || f.Provenance == "" || !f.RecordedAt.Valid() {
return fmt.Errorf("invalid focus frame")
}
return nil
}
func (t FocusTransition) Validate() error {
if t.TransitionID == "" || t.FrameID == "" || !ids.Revision(t.FromRevision).Valid() || !ids.Revision(t.ToRevision).Valid() || t.Operation == "" || !t.RecordedAt.Valid() {
return fmt.Errorf("invalid focus transition")
}
return nil
}
func validMatchPolicy(p MatchPolicy) bool {
return p == MatchRequired || p == MatchPreferred || p == MatchRelated || p == MatchExcluded
}
+22
View File
@@ -0,0 +1,22 @@
package situation_test
import (
"testing"
"git.cin.su/m/Assistant/contracts/identity"
contract "git.cin.su/m/Assistant/contracts/situation"
"git.cin.su/m/Assistant/platform/clock"
"git.cin.su/m/Assistant/platform/ids"
)
func TestFocusV2ContractsValidateTypedScopeAndFrame(t *testing.T) {
rev := ids.Revision(1)
scope := contract.ContextScope{ID: "scope", PrincipalID: identity.PrincipalID("company-a"), Revision: contract.FocusRevision(rev), RecordedAt: clock.Instant(1), Bindings: []contract.ContextBinding{{RoleKey: contract.RoleOrganization, TargetRef: contract.SemanticReference{OwnerNamespace: "world", SemanticKind: "organization", StableID: "a"}, MatchPolicy: contract.MatchRequired}}}
if err := scope.Validate(); err != nil {
t.Fatal(err)
}
frame := contract.FocusFrame{ID: "frame", PrincipalID: scope.PrincipalID, ActorID: "actor", Revision: 1, ContextScopeRef: contract.SemanticReference{OwnerNamespace: "situation", SemanticKind: "context_scope", StableID: ids.StableID(scope.ID), Revision: &rev}, State: contract.FocusActive, Provenance: contract.FocusExplicitHuman, RecordedAt: 1}
if err := frame.Validate(); err != nil {
t.Fatal(err)
}
}
+7
View File
@@ -0,0 +1,7 @@
package situation
import "git.cin.su/m/Assistant/platform/ids"
// SemanticReference keeps Situation references transport-neutral while
// ContextScope semantics remain owned by Situation.
type SemanticReference = ids.SemanticRef
+24
View File
@@ -0,0 +1,24 @@
package work
type ConsequenceAssessment struct {
ID string
TargetRefs []string
Impact int64
Reversibility int64
Uncertainty int64
Scope int64
Recoverability int64
CostOfError int64
ExpectedConsequences []string
MitigationOptions []string
RequiresDryRun bool
RequiresBackup bool
RecommendedConfirmation string
OwnerAccepted bool
EvidenceRefs []EvidenceRef
RecordedAtUnixMillis int64
}
func (a ConsequenceAssessment) Valid() bool {
return a.ID != "" && len(a.TargetRefs) > 0 && a.Impact >= 0 && a.Impact <= 1000 && a.Reversibility >= 0 && a.Reversibility <= 1000 && a.Uncertainty >= 0 && a.Uncertainty <= 1000 && a.Recoverability >= 0 && a.Recoverability <= 1000 && a.RecordedAtUnixMillis > 0
}
+28
View File
@@ -0,0 +1,28 @@
package work
import "git.cin.su/m/Assistant/contracts/world"
type FreshnessRequirementMode string
type FreshnessFallbackPolicy string
const (
FreshnessAny FreshnessRequirementMode = "ANY"
FreshnessPreferCurrent FreshnessRequirementMode = "PREFER_CURRENT"
FreshnessRequireCurrent FreshnessRequirementMode = "REQUIRE_CURRENT"
FreshnessRequireWithinAge FreshnessRequirementMode = "REQUIRE_WITHIN_AGE"
FreshnessRequireVersionMatch FreshnessRequirementMode = "REQUIRE_VERSION_MATCH"
FreshnessLiveRequired FreshnessRequirementMode = "LIVE_REQUIRED"
FallbackAllowStaleDisclosure FreshnessFallbackPolicy = "ALLOW_STALE_WITH_DISCLOSURE"
FallbackHypothesisOnly FreshnessFallbackPolicy = "USE_AS_HYPOTHESIS_ONLY"
FallbackWaitForSource FreshnessFallbackPolicy = "WAIT_FOR_SOURCE"
FallbackAskOwner FreshnessFallbackPolicy = "ASK_OWNER"
FallbackStopUnknown FreshnessFallbackPolicy = "STOP_WITH_UNKNOWN"
)
type TaskFreshnessRequirement struct {
Mode FreshnessRequirementMode
MaximumAgeMillis *int64
RequiredVersionRefs []world.SemanticReference
RevalidationRequired bool
FallbackPolicy FreshnessFallbackPolicy
}
+39
View File
@@ -0,0 +1,39 @@
package work
type EvolutionRunStage string
const (
EvolutionNeedRecorded EvolutionRunStage = "IMPROVEMENT_NEED"
EvolutionCandidateBuilt EvolutionRunStage = "CANDIDATE"
EvolutionIndependentlyEvaluated EvolutionRunStage = "INDEPENDENT_EVALUATION"
EvolutionSandboxed EvolutionRunStage = "SANDBOX_BUILD"
EvolutionBenchmarked EvolutionRunStage = "BENCHMARK"
EvolutionCanaried EvolutionRunStage = "CANARY"
EvolutionPromoted EvolutionRunStage = "PROMOTION"
EvolutionRolledBack EvolutionRunStage = "ROLLBACK"
)
type GovernedEvolutionResult struct {
NeedRef string
CandidateRef string
EvaluationRef string
Stages []EvolutionRunStage
EvidenceRefs []EvidenceRef
LearningLedgerOutcomeRef string
Promoted bool
RollbackRef string
}
// GovernedEvolutionOps are explicit gates. The caller supplies existing
// development executor/supervisor operations; this interface grants no new
// authority and has no autonomous promotion implementation.
type GovernedEvolutionOps struct {
CreateCandidate func() (EvolutionCandidate, error)
Evaluate func(EvolutionCandidate) (EvolutionEvaluation, error)
SandboxBuild func(EvolutionCandidate) (EvidenceRef, error)
Benchmark func(EvolutionCandidate) (EvidenceRef, bool, error)
Canary func(EvolutionCandidate) (EvidenceRef, bool, error)
Promote func(EvolutionCandidate, EvolutionEvaluation) (string, error)
Rollback func(EvolutionCandidate) (string, error)
LearningLedgerOutcome func(GovernedEvolutionResult) (string, error)
}
+51
View File
@@ -0,0 +1,51 @@
package work
type LongRunningWorkID string
type LongRunningState string
const (
LongRunningProposed LongRunningState = "PROPOSED"
LongRunningRunning LongRunningState = "RUNNING"
LongRunningPaused LongRunningState = "PAUSED"
LongRunningBlocked LongRunningState = "BLOCKED"
LongRunningCompleted LongRunningState = "COMPLETED"
LongRunningExhausted LongRunningState = "EXHAUSTED"
LongRunningCancelled LongRunningState = "CANCELLED"
)
type Investigation struct {
ID LongRunningWorkID
Objective string
HypothesisRefs []EvidenceRef
AttemptRefs []AgentRunID
FindingRefs []EvidenceRef
Blockers []string
CheckpointRefs []AgentCheckpointID
NextStep string
State LongRunningState
Revision int64
TimeBudgetMillis int64
CostBudgetMicros int64
MaxAttempts int
RecordedAtUnixMillis int64
}
// InvestigationCheckpoint is the durable boundary between attempts. A
// checkpoint is written only after an attempt has been verified, so a worker
// restart can resume at NextStep without replaying that attempt.
type InvestigationCheckpoint struct {
ID AgentCheckpointID
InvestigationID LongRunningWorkID
CompletedAttemptRefs []AgentRunID
CompletedFindingRefs []EvidenceRef
NextStep string
RecordedAtUnixMillis int64
}
func (c InvestigationCheckpoint) Valid() bool {
return c.ID != "" && c.InvestigationID != "" && c.NextStep != "" && c.RecordedAtUnixMillis > 0
}
func (w Investigation) Valid() bool {
return w.ID != "" && w.Objective != "" && w.State != "" && w.Revision > 0 && w.TimeBudgetMillis >= 0 && w.CostBudgetMicros >= 0 && w.MaxAttempts >= 0 && w.RecordedAtUnixMillis > 0
}
+32
View File
@@ -0,0 +1,32 @@
package work
type PerspectiveID string
type PerspectiveSpec struct {
ID PerspectiveID
ObjectiveLens string
FocusRef string
RetrievalProfileRef string
SkillRefs []string
ToolRefs []string
EvaluationCriteria []string
CapabilityRequirements []string
ExpectedOutputShape string
Critic bool
}
type SpecialistAssignment struct {
Perspective PerspectiveSpec
SubtaskRef string
FocusRef string
SkillRefs []string
ToolRefs []string
EvidenceRefs []EvidenceRef
}
type TeamDecision struct {
UseTeam bool
Reason string
Assignments []SpecialistAssignment
}
func (p PerspectiveSpec) Valid() bool {
return p.ID != "" && p.ObjectiveLens != "" && p.FocusRef != "" && len(p.SkillRefs) > 0 && len(p.ToolRefs) > 0 && len(p.EvaluationCriteria) > 0 && p.ExpectedOutputShape != ""
}
+36
View File
@@ -0,0 +1,36 @@
package work
type EvolutionChangeLevel string
const (
EvolutionKnowledge EvolutionChangeLevel = "KNOWLEDGE"
EvolutionBehavior EvolutionChangeLevel = "BEHAVIOR"
EvolutionCapability EvolutionChangeLevel = "CAPABILITY"
EvolutionCore EvolutionChangeLevel = "CORE"
)
type EvolutionCandidate struct {
ID string
ProposalRef string
ChangeLevel EvolutionChangeLevel
CreatorIdentity string
BaseVersionRef string
CandidateVersionRef string
MustNotWorsen []string
SandboxEvidenceRefs []EvidenceRef
BenchmarkEvidenceRefs []EvidenceRef
RollbackRef string
State string
}
type EvolutionEvaluation struct {
CandidateRef string
EvaluatorIdentity string
Approved bool
EvidenceRefs []EvidenceRef
MustNotWorsenPassed bool
RecordedAtUnixMillis int64
}
func (e EvolutionEvaluation) ValidFor(c EvolutionCandidate) bool {
return e.CandidateRef == c.ID && e.EvaluatorIdentity != "" && e.EvaluatorIdentity != c.CreatorIdentity && e.Approved && e.MustNotWorsenPassed && len(e.EvidenceRefs) > 0 && e.RecordedAtUnixMillis > 0
}
+322
View File
@@ -0,0 +1,322 @@
package world
import (
"fmt"
"git.cin.su/m/Assistant/contracts/identity"
"git.cin.su/m/Assistant/platform/clock"
"git.cin.su/m/Assistant/platform/ids"
)
// SemanticReference is the transport envelope used by World contracts. It is
// a reference only; it does not expose another owner's storage.
type SemanticReference = ids.SemanticRef
// VersionBinding is a typed applicability constraint. Absence of VersionRef
// means unknown, never an implicit "latest".
type VersionMatchMode string
const (
VersionExact VersionMatchMode = "EXACT"
VersionCompatibleFamily VersionMatchMode = "COMPATIBLE_FAMILY"
VersionAtOrBefore VersionMatchMode = "AT_OR_BEFORE"
VersionUnknown VersionMatchMode = "UNKNOWN"
)
type VersionBinding struct {
SubjectRef SemanticReference
VersionRef SemanticReference
MatchMode VersionMatchMode
}
type EnvironmentReference struct {
EnvironmentRef SemanticReference
VersionRef *SemanticReference
}
func (b VersionBinding) Validate() error {
if !b.SubjectRef.Valid() || !b.VersionRef.Valid() {
return fmt.Errorf("version binding references are invalid")
}
if b.MatchMode != VersionExact && b.MatchMode != VersionCompatibleFamily && b.MatchMode != VersionAtOrBefore && b.MatchMode != VersionUnknown {
return fmt.Errorf("version binding match mode is invalid")
}
return nil
}
func (r EnvironmentReference) Validate() error {
if !r.EnvironmentRef.Valid() {
return fmt.Errorf("environment reference is invalid")
}
if r.VersionRef != nil && !r.VersionRef.Valid() {
return fmt.Errorf("environment version reference is invalid")
}
return nil
}
type PrincipalRealm string
const (
RealmPersonal PrincipalRealm = "PERSONAL"
RealmShared PrincipalRealm = "SHARED"
RealmPublic PrincipalRealm = "PUBLIC"
RealmSystem PrincipalRealm = "SYSTEM"
)
type SensitivityClass string
const (
SensitivityPublic SensitivityClass = "PUBLIC"
SensitivityPrivate SensitivityClass = "PRIVATE"
SensitivityRestricted SensitivityClass = "RESTRICTED"
SensitivitySecretReference SensitivityClass = "SECRET_REFERENCE"
)
type ValueTypeKind string
const (
ValueString ValueTypeKind = "STRING"
ValueInteger ValueTypeKind = "INTEGER"
ValueDecimal ValueTypeKind = "DECIMAL"
ValueBoolean ValueTypeKind = "BOOLEAN"
ValueTime ValueTypeKind = "TIME"
ValueDuration ValueTypeKind = "DURATION"
ValueEnum ValueTypeKind = "ENUM"
ValueReference ValueTypeKind = "REFERENCE"
ValueBinaryRef ValueTypeKind = "BINARY_REF"
ValueList ValueTypeKind = "LIST"
ValueStruct ValueTypeKind = "STRUCT"
)
type ValueField struct {
Name string
Type ValueTypeSpec
}
type ValueTypeSpec struct {
Kind ValueTypeKind
Element *ValueTypeSpec
Fields []ValueField
EnumValues []string
ReferenceKind string
}
type WorldObjectID ids.StableID
type KindDefinitionID ids.StableID
type WorldAliasID ids.StableID
type PersonReferent struct {
WorldObjectRef SemanticReference
DisplayName string
ConfidenceMillis int64
}
func (p PersonReferent) Valid() bool {
return p.WorldObjectRef.Valid() && p.DisplayName != "" && p.ConfidenceMillis >= 0 && p.ConfidenceMillis <= 1000
}
type FacetDefinitionID ids.StableID
type RelationDefinitionID ids.StableID
type ResolutionDecisionID ids.StableID
type LineageID ids.StableID
type LifecycleState string
const (
LifecycleActive LifecycleState = "ACTIVE"
LifecycleMerged LifecycleState = "MERGED"
LifecycleSplit LifecycleState = "SPLIT"
LifecycleRetired LifecycleState = "RETIRED"
LifecycleUnknownIdentity LifecycleState = "UNKNOWN_IDENTITY"
)
type WorldObject struct {
ID WorldObjectID
PrincipalID identity.PrincipalID
KindDefinitionRef SemanticReference
KindRevision ids.Revision
Lifecycle LifecycleState
CreatedAt clock.Instant
}
type WorldObjectKindDefinition struct {
ID KindDefinitionID
KindKey string
Revision ids.Revision
DisplayName string
ParentKindRef *SemanticReference
Lifecycle LifecycleState
DefinitionDigest string
RecordedAt clock.Instant
}
type WorldAlias struct {
ID WorldAliasID
PrincipalID identity.PrincipalID
ObjectID WorldObjectID
Alias string
RecordedAt clock.Instant
}
type FacetDefinition struct {
ID FacetDefinitionID
KindKey string
Revision ids.Revision
FacetKey string
ValueType ValueTypeSpec
DefinitionDigest string
RecordedAt clock.Instant
}
type RelationDefinition struct {
ID RelationDefinitionID
KindKey string
Revision ids.Revision
RelationKey string
TargetKindKey string
DefinitionDigest string
RecordedAt clock.Instant
}
type ResolutionDecision string
const (
ResolutionSame ResolutionDecision = "SAME"
ResolutionDistinct ResolutionDecision = "DISTINCT"
ResolutionMerge ResolutionDecision = "MERGE"
ResolutionSplit ResolutionDecision = "SPLIT"
ResolutionUnresolved ResolutionDecision = "UNRESOLVED"
)
type IdentityResolutionCandidate struct {
ObjectRef SemanticReference
Evidence []SemanticReference
Confidence int64
}
type IdentityResolutionDecisionRecord struct {
ID ResolutionDecisionID
PrincipalID identity.PrincipalID
Candidates []IdentityResolutionCandidate
Decision ResolutionDecision
Evidence []SemanticReference
ConfidenceMillis int64
DecidedAt clock.Instant
Revision ids.Revision
}
type WorldLineage struct {
ID LineageID
Operation ResolutionDecision
SourceRefs []SemanticReference
SuccessorRefs []SemanticReference
RecordedAt clock.Instant
}
func (w WorldObject) Validate() error {
if w.ID == "" || !w.KindDefinitionRef.Valid() || !w.KindRevision.Valid() || !validLifecycle(w.Lifecycle) || !w.CreatedAt.Valid() {
return fmt.Errorf("world object is incomplete")
}
return nil
}
func (k WorldObjectKindDefinition) Validate() error {
if k.ID == "" || k.KindKey == "" || !k.Revision.Valid() || k.DisplayName == "" || !validLifecycle(k.Lifecycle) || k.DefinitionDigest == "" || !k.RecordedAt.Valid() {
return fmt.Errorf("world kind definition is incomplete")
}
if k.ParentKindRef != nil && !k.ParentKindRef.Valid() {
return fmt.Errorf("world kind parent reference is invalid")
}
return nil
}
func (a WorldAlias) Validate() error {
if a.ID == "" || a.ObjectID == "" || a.Alias == "" || !a.RecordedAt.Valid() {
return fmt.Errorf("world alias is incomplete")
}
return nil
}
func (f FacetDefinition) Validate() error {
if f.ID == "" || f.KindKey == "" || !f.Revision.Valid() || f.FacetKey == "" || f.DefinitionDigest == "" || !f.RecordedAt.Valid() {
return fmt.Errorf("facet definition is incomplete")
}
return f.ValueType.Validate()
}
func (r RelationDefinition) Validate() error {
if r.ID == "" || r.KindKey == "" || !r.Revision.Valid() || r.RelationKey == "" || r.TargetKindKey == "" || r.DefinitionDigest == "" || !r.RecordedAt.Valid() {
return fmt.Errorf("relation definition is incomplete")
}
return nil
}
func (d IdentityResolutionDecisionRecord) Validate() error {
if d.ID == "" || !validDecision(d.Decision) || len(d.Candidates) == 0 || d.ConfidenceMillis < 0 || !d.DecidedAt.Valid() || !d.Revision.Valid() {
return fmt.Errorf("identity resolution decision is incomplete")
}
for _, candidate := range d.Candidates {
if !candidate.ObjectRef.Valid() || candidate.Confidence < 0 || candidate.Confidence > 1000 {
return fmt.Errorf("identity resolution candidate is invalid")
}
for _, evidence := range candidate.Evidence {
if !evidence.Valid() {
return fmt.Errorf("identity resolution evidence reference is invalid")
}
}
}
return nil
}
func (l WorldLineage) Validate() error {
if l.ID == "" || (l.Operation != ResolutionMerge && l.Operation != ResolutionSplit) || len(l.SourceRefs) == 0 || len(l.SuccessorRefs) == 0 || !l.RecordedAt.Valid() {
return fmt.Errorf("world lineage is incomplete")
}
return nil
}
func validLifecycle(value LifecycleState) bool {
return value == LifecycleActive || value == LifecycleMerged || value == LifecycleSplit || value == LifecycleRetired || value == LifecycleUnknownIdentity
}
func validDecision(value ResolutionDecision) bool {
return value == ResolutionSame || value == ResolutionDistinct || value == ResolutionMerge || value == ResolutionSplit || value == ResolutionUnresolved
}
func (s ValueTypeSpec) Validate() error {
if s.Kind == "" {
return fmt.Errorf("value type kind is required")
}
switch s.Kind {
case ValueList:
if s.Element == nil {
return fmt.Errorf("list element type is required")
}
return s.Element.Validate()
case ValueStruct:
if len(s.Fields) == 0 {
return fmt.Errorf("struct fields are required")
}
seen := map[string]struct{}{}
for _, field := range s.Fields {
if field.Name == "" {
return fmt.Errorf("struct field name is required")
}
if _, ok := seen[field.Name]; ok {
return fmt.Errorf("duplicate struct field %q", field.Name)
}
seen[field.Name] = struct{}{}
if err := field.Type.Validate(); err != nil {
return fmt.Errorf("field %s: %w", field.Name, err)
}
}
case ValueEnum:
if len(s.EnumValues) == 0 {
return fmt.Errorf("enum values are required")
}
case ValueReference:
if s.ReferenceKind == "" {
return fmt.Errorf("reference kind is required")
}
}
return nil
}
+17
View File
@@ -0,0 +1,17 @@
package world
import "testing"
func TestValueTypeSpecValidatesTypedRecursiveShape(t *testing.T) {
spec := ValueTypeSpec{Kind: ValueStruct, Fields: []ValueField{{Name: "name", Type: ValueTypeSpec{Kind: ValueString}}, {Name: "refs", Type: ValueTypeSpec{Kind: ValueList, Element: &ValueTypeSpec{Kind: ValueReference, ReferenceKind: "world.object"}}}}}
if err := spec.Validate(); err != nil {
t.Fatalf("ValueTypeSpec.Validate() = %v", err)
}
}
func TestValueTypeSpecRejectsDuplicateFields(t *testing.T) {
spec := ValueTypeSpec{Kind: ValueStruct, Fields: []ValueField{{Name: "same", Type: ValueTypeSpec{Kind: ValueString}}, {Name: "same", Type: ValueTypeSpec{Kind: ValueString}}}}
if err := spec.Validate(); err == nil {
t.Fatal("duplicate fields were accepted")
}
}
+22
View File
@@ -0,0 +1,22 @@
package world
import (
"testing"
"git.cin.su/m/Assistant/platform/clock"
"git.cin.su/m/Assistant/platform/ids"
)
func TestWorldObjectValidationKeepsReferentSeparateFromClaims(t *testing.T) {
object := WorldObject{ID: "object-1", KindDefinitionRef: ids.SemanticRef{OwnerNamespace: "world", SemanticKind: "kind", StableID: "kind-1"}, KindRevision: 1, Lifecycle: LifecycleActive, CreatedAt: clock.Instant(1)}
if err := object.Validate(); err != nil {
t.Fatalf("WorldObject.Validate() = %v", err)
}
}
func TestIdentityResolutionRequiresEvidenceBackedCandidates(t *testing.T) {
decision := IdentityResolutionDecisionRecord{ID: "decision-1", Decision: ResolutionSame, Candidates: []IdentityResolutionCandidate{{ObjectRef: ids.SemanticRef{OwnerNamespace: "world", SemanticKind: "object", StableID: "object-1"}, Confidence: 900}}, DecidedAt: clock.Instant(1), Revision: 1}
if err := decision.Validate(); err != nil {
t.Fatalf("IdentityResolutionDecisionRecord.Validate() = %v", err)
}
}
@@ -0,0 +1,82 @@
BEGIN;
CREATE SCHEMA IF NOT EXISTS world;
SET ROLE world_role;
CREATE TABLE IF NOT EXISTS world.kind_definitions (
kind_definition_id TEXT PRIMARY KEY,
kind_key TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
display_name TEXT NOT NULL,
parent_owner_namespace TEXT NOT NULL DEFAULT '',
parent_semantic_kind TEXT NOT NULL DEFAULT '',
parent_stable_id TEXT NOT NULL DEFAULT '',
parent_revision BIGINT,
lifecycle TEXT NOT NULL,
definition_digest TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0),
UNIQUE (kind_key, revision)
);
CREATE TABLE IF NOT EXISTS world.objects (
world_object_id TEXT PRIMARY KEY,
principal_id TEXT,
kind_owner_namespace TEXT NOT NULL,
kind_semantic_kind TEXT NOT NULL,
kind_stable_id TEXT NOT NULL,
kind_revision BIGINT,
lifecycle TEXT NOT NULL,
created_at_unix_millis BIGINT NOT NULL CHECK (created_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS world.aliases (
world_alias_id TEXT PRIMARY KEY,
principal_id TEXT,
world_object_id TEXT NOT NULL,
alias TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS world.facet_definitions (
facet_definition_id TEXT PRIMARY KEY,
kind_key TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
facet_key TEXT NOT NULL,
value_type JSONB NOT NULL,
definition_digest TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0),
UNIQUE (kind_key, facet_key, revision)
);
CREATE TABLE IF NOT EXISTS world.relation_definitions (
relation_definition_id TEXT PRIMARY KEY,
kind_key TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
relation_key TEXT NOT NULL,
target_kind_key TEXT NOT NULL,
definition_digest TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0),
UNIQUE (kind_key, relation_key, revision)
);
CREATE TABLE IF NOT EXISTS world.identity_resolution_decisions (
resolution_decision_id TEXT PRIMARY KEY,
principal_id TEXT,
candidates JSONB NOT NULL,
decision TEXT NOT NULL,
evidence JSONB NOT NULL,
confidence_millis BIGINT NOT NULL CHECK (confidence_millis >= 0),
decided_at_unix_millis BIGINT NOT NULL CHECK (decided_at_unix_millis > 0),
revision BIGINT NOT NULL CHECK (revision > 0)
);
CREATE TABLE IF NOT EXISTS world.lineage (
lineage_id TEXT PRIMARY KEY,
operation TEXT NOT NULL,
source_refs JSONB NOT NULL,
successor_refs JSONB NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
RESET ROLE;
COMMIT;
@@ -0,0 +1,47 @@
BEGIN;
SET ROLE situation_role;
CREATE TABLE IF NOT EXISTS situation.context_scopes (
context_scope_id TEXT PRIMARY KEY,
principal_id TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
bindings JSONB NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS situation.focus_frames (
focus_frame_id TEXT PRIMARY KEY,
principal_id TEXT NOT NULL,
actor_id TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
authority_scope_ref TEXT NOT NULL,
context_scope_ref JSONB NOT NULL,
goal_ref TEXT,
task_ref TEXT,
source_utterance_ref TEXT,
provenance TEXT NOT NULL,
confidence_millis BIGINT NOT NULL CHECK (confidence_millis >= 0),
state TEXT NOT NULL,
parent_frame_ref TEXT,
activated_at_unix_millis BIGINT NOT NULL CHECK (activated_at_unix_millis > 0),
suspended_at_unix_millis BIGINT,
expired_at_unix_millis BIGINT,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS situation.focus_transitions (
transition_id TEXT PRIMARY KEY,
focus_frame_id TEXT NOT NULL,
from_revision BIGINT NOT NULL CHECK (from_revision > 0),
to_revision BIGINT NOT NULL CHECK (to_revision > 0),
operation TEXT NOT NULL,
cause_ref TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
CREATE INDEX IF NOT EXISTS focus_transitions_frame_order ON situation.focus_transitions(focus_frame_id, recorded_at_unix_millis, transition_id);
GRANT SELECT, INSERT, UPDATE ON situation.context_scopes, situation.focus_frames, situation.focus_transitions TO situation_role;
RESET ROLE;
COMMIT;
@@ -0,0 +1,7 @@
BEGIN;
SET ROLE configuration_role;
CREATE TABLE IF NOT EXISTS configuration.setting_definitions (setting_definition_id TEXT PRIMARY KEY, owner_namespace TEXT NOT NULL, stable_key TEXT NOT NULL, revision BIGINT NOT NULL CHECK(revision>0), value_type TEXT NOT NULL, default_value TEXT, sensitivity TEXT NOT NULL, lifecycle TEXT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL);
CREATE TABLE IF NOT EXISTS configuration.setting_assignments (setting_assignment_id TEXT PRIMARY KEY, principal_id TEXT NOT NULL, definition_ref JSONB NOT NULL, revision BIGINT NOT NULL CHECK(revision>0), selector JSONB NOT NULL, typed_value TEXT, secret_ref TEXT, effective_from_unix_millis BIGINT NOT NULL, effective_until_unix_millis BIGINT, source TEXT NOT NULL, source_ref TEXT NOT NULL, lifecycle TEXT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL);
GRANT SELECT, INSERT, UPDATE ON configuration.setting_definitions, configuration.setting_assignments TO configuration_role;
RESET ROLE;
COMMIT;
@@ -0,0 +1,7 @@
BEGIN;
SET ROLE self_role;
CREATE TABLE IF NOT EXISTS self.competence_assessments (assessment_id TEXT PRIMARY KEY, principal_id TEXT NOT NULL, subject_ref JSONB NOT NULL, revision BIGINT NOT NULL CHECK(revision>0), context_matcher JSONB NOT NULL, confidence_millis BIGINT NOT NULL, evidence_refs JSONB NOT NULL, assessed_at_unix_millis BIGINT NOT NULL);
CREATE TABLE IF NOT EXISTS self.learning_ledger (entry_id TEXT PRIMARY KEY, principal_id TEXT NOT NULL, observed_problem TEXT NOT NULL, evidence_refs JSONB NOT NULL, diagnosis TEXT NOT NULL, hypothesis TEXT NOT NULL, decision TEXT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL);
GRANT SELECT, INSERT, UPDATE ON self.competence_assessments, self.learning_ledger TO self_role;
RESET ROLE;
COMMIT;
@@ -0,0 +1,22 @@
BEGIN;
SET ROLE work_role;
CREATE TABLE IF NOT EXISTS work.long_running_work (
investigation_id TEXT PRIMARY KEY, objective TEXT NOT NULL,
hypothesis_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], attempt_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[],
finding_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], blockers TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[],
checkpoint_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], next_step TEXT NOT NULL, state TEXT NOT NULL,
revision BIGINT NOT NULL, time_budget_millis BIGINT NOT NULL, cost_budget_micros BIGINT NOT NULL,
max_attempts INTEGER NOT NULL, recorded_at_unix_millis BIGINT NOT NULL,
CHECK (investigation_id <> ''), CHECK (objective <> ''), CHECK (next_step <> ''), CHECK (revision > 0), CHECK (time_budget_millis >= 0), CHECK (cost_budget_micros >= 0), CHECK (max_attempts >= 0), CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS work.investigation_checkpoints (
checkpoint_id TEXT PRIMARY KEY, investigation_id TEXT NOT NULL, completed_attempt_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[],
completed_finding_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], next_step TEXT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL,
CHECK (checkpoint_id <> ''), CHECK (investigation_id <> ''), CHECK (next_step <> ''), CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS work.investigation_attempts (
investigation_id TEXT NOT NULL, attempt_ref TEXT NOT NULL, verified_at_unix_millis BIGINT NOT NULL,
PRIMARY KEY (investigation_id, attempt_ref), CHECK (investigation_id <> ''), CHECK (attempt_ref <> ''), CHECK (verified_at_unix_millis > 0)
);
RESET ROLE;
COMMIT;
@@ -0,0 +1,11 @@
BEGIN;
SET ROLE identity_role;
CREATE TABLE IF NOT EXISTS identity.principal_data_realms (
realm_id TEXT PRIMARY KEY, owner_principal_id TEXT NOT NULL, realm_kind TEXT NOT NULL,
member_principal_ids TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], shared BOOLEAN NOT NULL DEFAULT FALSE,
revision BIGINT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL,
CHECK (realm_id <> ''), CHECK (owner_principal_id <> ''), CHECK (realm_kind IN ('PERSONAL','SHARED','PUBLIC')),
CHECK (realm_kind <> 'SHARED' OR shared), CHECK (revision > 0), CHECK (recorded_at_unix_millis > 0)
);
RESET ROLE;
COMMIT;
+1 -5
View File
@@ -1,5 +1 @@
{
"task_file": "dev/tasks/GEN2-001-accept-gen2-owner-registry-and-dependency-rules.json",
"task_id": "GEN2-001",
"task_revision": 1
}
{"task_file":"dev/tasks/GEN2-024-multi-person-realms-identity-boundaries-and-contextual-source-trust.json","task_id":"GEN2-024","task_revision":1}
@@ -0,0 +1,15 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/capability"
"testing"
)
func TestStrategyUsesRiskAndCostSignals(t *testing.T) {
if got := (capability.StrategyRequest{RequiredQuality: 400, CostBudgetMicros: 10}).Select().Path; got != capability.PathRule {
t.Fatal(got)
}
if got := (capability.StrategyRequest{RiskClass: "HIGH", CostOfError: 900}).Select(); got.Path != capability.PathStrongLocal || !got.Escalate {
t.Fatalf("%#v", got)
}
}
+22
View File
@@ -0,0 +1,22 @@
package domain
import (
"fmt"
"git.cin.su/m/Assistant/contracts/capability"
)
func ValidateReflexRevision(v capability.ReflexRevision) error {
if v.ReflexID == "" || v.SourceSkillRevision < 1 || v.Kind == "" || v.ImplementationRef == "" || v.Lifecycle == "" || v.RecordedAt < 1 {
return fmt.Errorf("invalid reflex revision")
}
if v.Lifecycle == capability.ReflexActive && len(v.ValidationEvidenceRefs) == 0 {
return fmt.Errorf("active reflex requires evidence")
}
return nil
}
func ReflexFallback(d capability.FastPathDecision) string {
if d.Decision == capability.FastPathApplied {
return "reflex"
}
return "skill->reasoning"
}
+21
View File
@@ -0,0 +1,21 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/capability"
"git.cin.su/m/Assistant/modules/capability/domain"
"testing"
)
func TestReflexActiveRequiresEvidenceAndFallbacks(t *testing.T) {
v := capability.ReflexRevision{ReflexID: "r", SourceSkillRevision: 1, Kind: capability.ReflexRule, ImplementationRef: "rule", Lifecycle: capability.ReflexActive, RecordedAt: 1}
if domain.ValidateReflexRevision(v) == nil {
t.Fatal("active reflex without evidence")
}
v.ValidationEvidenceRefs = []capability.SkillEvidenceRef{"eval"}
if err := domain.ValidateReflexRevision(v); err != nil {
t.Fatal(err)
}
if domain.ReflexFallback(capability.FastPathDecision{Decision: capability.FastPathEscalate}) != "skill->reasoning" {
t.Fatal("missing escalation")
}
}
+16
View File
@@ -0,0 +1,16 @@
package domain
import (
"fmt"
"git.cin.su/m/Assistant/contracts/capability"
)
func ValidateSkillRevision(value capability.SkillRevision) error {
if value.SkillID == "" || value.Revision < 1 || value.ImplementationRef == "" || value.Lifecycle == "" || value.RecordedAt < 1 {
return fmt.Errorf("invalid skill revision")
}
if value.Lifecycle == capability.SkillValidated && len(value.ValidationEvidenceRefs) == 0 {
return fmt.Errorf("validated skill requires evidence")
}
return nil
}
+4
View File
@@ -0,0 +1,4 @@
# configuration
Configuration owns typed, scoped, versioned settings. ENV is limited to
bootstrap primitives; secret values are never configuration values.
@@ -0,0 +1,41 @@
package domain
import (
"fmt"
"git.cin.su/m/Assistant/contracts/configuration"
"sort"
)
var ErrInvalidConfigurationCommand = fmt.Errorf("invalid conversational configuration command")
func Resolve(definition configuration.SettingDefinition, assignments []configuration.SettingAssignment, selector configuration.ScopeSelector) (configuration.EffectiveSetting, error) {
if err := definition.Validate(); err != nil {
return configuration.EffectiveSetting{}, err
}
var matches []configuration.SettingAssignment
for _, a := range assignments {
if err := a.Validate(); err != nil {
return configuration.EffectiveSetting{}, err
}
if a.DefinitionRef == string(definition.ID) && a.Lifecycle == configuration.SettingActive && a.Selector.PrincipalRef == selector.PrincipalRef && a.Selector.SkillRef == selector.SkillRef {
matches = append(matches, a)
}
}
if len(matches) == 0 {
return configuration.EffectiveSetting{DefinitionRef: string(definition.ID), Value: definition.DefaultValue, ResolutionTrace: []string{"system-default"}}, nil
}
sort.SliceStable(matches, func(i, j int) bool { return specificity(matches[i].Selector) > specificity(matches[j].Selector) })
if len(matches) > 1 && specificity(matches[0].Selector) == specificity(matches[1].Selector) {
return configuration.EffectiveSetting{}, fmt.Errorf("configuration conflict")
}
return configuration.EffectiveSetting{DefinitionRef: string(definition.ID), Value: matches[0].TypedValue, WinningAssignmentRef: string(matches[0].ID), ResolutionTrace: []string{"specificity-selected"}}, nil
}
func specificity(s configuration.ScopeSelector) int {
return len(s.RequiredContextBindings) + boolInt(s.SkillRef != "") + boolInt(s.TaskRef != "") + boolInt(s.SessionRef != "") + boolInt(s.TemporaryOverride)
}
func boolInt(v bool) int {
if v {
return 1
}
return 0
}
@@ -0,0 +1,3 @@
package domain_test
import("testing"; "git.cin.su/m/Assistant/contracts/configuration"; "git.cin.su/m/Assistant/modules/configuration/domain")
func TestConfigurationResolvesCompanyAndSkillScope(t *testing.T){d:=configuration.SettingDefinition{ID:"x",OwnerNamespace:"capability",StableKey:"endpoint",Revision:1,ValueType:configuration.ValueString,Lifecycle:configuration.SettingActive,RecordedAtUnixMillis:1};a:=configuration.SettingAssignment{ID:"a",PrincipalID:"company-a",DefinitionRef:"x",Revision:1,Selector:configuration.ScopeSelector{PrincipalRef:"company-a",SkillRef:"skill"},TypedValue:"a-value",Source:configuration.SourceHumanDirective,Lifecycle:configuration.SettingActive,RecordedAtUnixMillis:1};got,err:=domain.Resolve(d,[]configuration.SettingAssignment{a},configuration.ScopeSelector{PrincipalRef:"company-a",SkillRef:"skill"});if err!=nil||got.Value!="a-value"{t.Fatalf("got %#v err=%v",got,err)}}
@@ -0,0 +1,32 @@
package domain
import (
"fmt"
"git.cin.su/m/Assistant/contracts/configuration"
"git.cin.su/m/Assistant/platform/ids"
"strings"
"time"
)
var ErrConfigurationAuthorityRequired = fmt.Errorf("configuration change requires Authority and Commit")
func AssignmentFromConversation(kind, principalID, definitionRef, typedValue, sessionRef, sourceRef string, temporaryOverride bool, definition configuration.SettingDefinition, now time.Time) (configuration.SettingAssignment, error) {
if kind != "SET" || principalID == "" || definitionRef != string(definition.ID) || strings.TrimSpace(typedValue) == "" || now.IsZero() || definition.ValueType == configuration.ValueSecretRef {
return configuration.SettingAssignment{}, ErrInvalidConfigurationCommand
}
if sourceRef == "" {
return configuration.SettingAssignment{}, ErrInvalidConfigurationCommand
}
id, err := ids.New()
if err != nil {
return configuration.SettingAssignment{}, err
}
return configuration.SettingAssignment{ID: configuration.SettingAssignmentID(id), PrincipalID: principalID, DefinitionRef: string(definition.ID), DefinitionRevision: definition.Revision, Revision: 1, Selector: configuration.ScopeSelector{PrincipalRef: principalID, SessionRef: sessionRef, TemporaryOverride: temporaryOverride}, TypedValue: strings.TrimSpace(typedValue), Source: configuration.SourceHumanDirective, SourceRef: sourceRef, Lifecycle: configuration.SettingActive, RecordedAtUnixMillis: now.UnixMilli()}, nil
}
func ExplainEffectiveSetting(definition configuration.SettingDefinition, effective configuration.EffectiveSetting) string {
if effective.WinningAssignmentRef == "" {
return fmt.Sprintf("Настройка %s сейчас имеет системное значение %q.", definition.StableKey, effective.Value)
}
return fmt.Sprintf("Настройка %s сейчас имеет значение %q; применено scoped-правило %s.", definition.StableKey, effective.Value, effective.WinningAssignmentRef)
}
@@ -0,0 +1,23 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/configuration"
"git.cin.su/m/Assistant/modules/configuration/domain"
"testing"
"time"
)
func TestConversationCreatesScopedAssignmentWithoutBypassingAuthority(t *testing.T) {
d := configuration.SettingDefinition{ID: "setting:language", OwnerNamespace: "interaction", StableKey: "language", Revision: 2, ValueType: configuration.ValueString, Lifecycle: configuration.SettingActive, RecordedAtUnixMillis: 1}
a, err := domain.AssignmentFromConversation("SET", "principal-1", "setting:language", "ru", "session-1", "utterance-1", true, d, time.UnixMilli(2))
if err != nil || a.Selector.PrincipalRef != "principal-1" || !a.Selector.TemporaryOverride || a.Source != configuration.SourceHumanDirective {
t.Fatalf("assignment=%+v err=%v", a, err)
}
}
func TestSecretConfigurationCannotReceiveConversationalValue(t *testing.T) {
d := configuration.SettingDefinition{ID: "setting:key", OwnerNamespace: "capability", StableKey: "key", Revision: 1, ValueType: configuration.ValueSecretRef, Lifecycle: configuration.SettingActive, RecordedAtUnixMillis: 1}
if _, err := domain.AssignmentFromConversation("SET", "p", string(d.ID), "secret", "", "u", false, d, time.UnixMilli(2)); err == nil {
t.Fatal("secret value accepted")
}
}
+29
View File
@@ -0,0 +1,29 @@
package domain
import (
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/platform/ids"
"strings"
)
func BuildEpisode(experiences []epistemics.ExperienceRecord, summary string, at int64) (epistemics.Episode, error) {
if len(experiences) == 0 || strings.TrimSpace(summary) == "" || at < 1 {
return epistemics.Episode{}, ErrInvalidExperience
}
refs := make([]epistemics.ExperienceRecordID, 0, len(experiences))
outcome := epistemics.OutcomeUnknown
for _, e := range experiences {
if _, err := NewExperienceRecord(e); err != nil {
return epistemics.Episode{}, err
}
refs = append(refs, e.ID)
if e.ActualOutcome != epistemics.OutcomeSuccess {
outcome = e.ActualOutcome
}
}
id, err := ids.New()
if err != nil {
return epistemics.Episode{}, err
}
return epistemics.Episode{ID: epistemics.EpisodeID(id), ExperienceRefs: refs, Summary: summary, Outcome: outcome, RecordedAtUnixMillis: at}, nil
}
+15
View File
@@ -0,0 +1,15 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/modules/epistemics/domain"
"testing"
)
func TestEpisodeIsRebuildableFromExperience(t *testing.T) {
e := epistemics.ExperienceRecord{ID: "e", SourceKind: epistemics.ExperienceSourceInteraction, OriginalIntentID: "i", SourceUtteranceID: "u", HelpMethod: epistemics.HelpMethodFallback, ExpectedOutcome: epistemics.OutcomeSuccess, ActualOutcome: epistemics.OutcomeFailed, RecordedAtUnixMillis: 1}
ep, err := domain.BuildEpisode([]epistemics.ExperienceRecord{e}, "failed attempt", 1)
if err != nil || len(ep.ExperienceRefs) != 1 || ep.Outcome != epistemics.OutcomeFailed {
t.Fatalf("episode=%#v err=%v", ep, err)
}
}
+30
View File
@@ -0,0 +1,30 @@
package domain
import "git.cin.su/m/Assistant/contracts/epistemics"
// AssessFreshness receives the Work-owned requirement as primitive policy
// inputs, keeping the Epistemics owner independent of Work package types.
func AssessFreshness(applicability epistemics.TemporalApplicability, mode string, maximumAgeMillis *int64, nowMillis int64) epistemics.FreshnessAssessment {
age := nowMillis - applicability.ObservedAtUnixMillis
if age < 0 {
age = 0
}
state := epistemics.FreshnessAssessmentCurrent
reason := "observation is within applicability window"
if applicability.ValidUntilUnixMillis != nil && nowMillis > *applicability.ValidUntilUnixMillis {
state, reason = epistemics.FreshnessAssessmentStale, "valid-until elapsed"
}
if applicability.Volatility.HardStaleAfterMillis != nil && age > *applicability.Volatility.HardStaleAfterMillis {
state, reason = epistemics.FreshnessAssessmentStale, "hard volatility window elapsed"
}
if applicability.Volatility.RevalidateAfterMillis != nil && age > *applicability.Volatility.RevalidateAfterMillis && state == epistemics.FreshnessAssessmentCurrent {
state, reason = epistemics.FreshnessAssessmentAging, "revalidation window elapsed"
}
if maximumAgeMillis != nil && age > *maximumAgeMillis {
state, reason = epistemics.FreshnessAssessmentStale, "task maximum age exceeded"
}
if mode == "LIVE_REQUIRED" {
state, reason = epistemics.FreshnessAssessmentHistoricalOnly, "live source required"
}
return epistemics.FreshnessAssessment{SourceKnowledgeRef: "knowledge", TaskRef: "task", State: state, Reason: reason, AgeMillis: age, AssessedAtUnixMillis: nowMillis}
}
@@ -0,0 +1,17 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/modules/epistemics/domain"
"testing"
)
func TestFreshnessIsTaskRelative(t *testing.T) {
hard := int64(100)
app := epistemics.TemporalApplicability{ObservedAtUnixMillis: 1, Volatility: epistemics.VolatilitySpec{Mode: epistemics.VolatilityVersionBound, HardStaleAfterMillis: &hard}}
current := domain.AssessFreshness(app, "ANY", nil, 50)
historical := domain.AssessFreshness(app, "LIVE_REQUIRED", nil, 50)
if current.State != epistemics.FreshnessAssessmentCurrent || historical.State != epistemics.FreshnessAssessmentHistoricalOnly {
t.Fatalf("got %v and %v", current.State, historical.State)
}
}
+36
View File
@@ -0,0 +1,36 @@
package domain
import (
"errors"
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/platform/ids"
"strings"
)
var ErrInvalidKnowledge = errors.New("invalid epistemic knowledge record")
func ValidateProposition(value epistemics.Proposition) error {
if value.ID == "" || value.Kind == "" || strings.TrimSpace(value.SubjectRef) == "" || (value.ObjectValue == "" && value.ObjectRef == "" && value.TextFallback == "") {
return ErrInvalidKnowledge
}
return nil
}
func ValidateBeliefAssessment(value epistemics.BeliefAssessment) error {
if value.ID == "" || value.ClaimID == "" || !value.Revision.Valid() || value.State == "" || value.ConfidenceMillis < 0 || value.ConfidenceMillis > 1000 || value.AssessedAtUnixMillis < 1 {
return ErrInvalidKnowledge
}
return nil
}
func NewBeliefAssessment(claim epistemics.ClaimID, confidence int64, state epistemics.BeliefAssessmentState, evidence []epistemics.EvidenceRef, at int64) (epistemics.BeliefAssessment, error) {
id, err := ids.New()
if err != nil {
return epistemics.BeliefAssessment{}, err
}
value := epistemics.BeliefAssessment{ID: id, ClaimID: claim, Revision: ids.InitialRevision, State: state, ConfidenceMillis: confidence, EvidenceRefs: append([]epistemics.EvidenceRef(nil), evidence...), AssessedAtUnixMillis: at}
if err := ValidateBeliefAssessment(value); err != nil {
return epistemics.BeliefAssessment{}, err
}
return value, nil
}
@@ -0,0 +1,22 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/modules/epistemics/domain"
"testing"
)
func TestKnowledgeV2SeparatesPropositionAndReassessableBelief(t *testing.T) {
p := epistemics.Proposition{ID: "p", Kind: epistemics.PropositionWorldFacet, SubjectRef: "world:database:a", ObjectValue: "1.6.28"}
if err := domain.ValidateProposition(p); err != nil {
t.Fatal(err)
}
a, err := domain.NewBeliefAssessment("claim:a", 800, epistemics.BeliefAssessmentCurrent, []epistemics.EvidenceRef{"observation:a"}, 1)
if err != nil {
t.Fatal(err)
}
a.Revision++
if err := domain.ValidateBeliefAssessment(a); err != nil {
t.Fatal(err)
}
}
+35
View File
@@ -0,0 +1,35 @@
package domain
import (
"errors"
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/platform/ids"
)
var ErrInvalidOutcomeAssessment = errors.New("invalid world outcome assessment")
// AssessWorldOutcome keeps Commit's execution fact separate from Epistemics'
// observation. No observation means UNKNOWN; a transport receipt alone never
// becomes success.
func AssessWorldOutcome(principalID, attemptRef, expectedEffect string, receiptRefs []string, observationRefs []epistemics.ObservationID, claimRefs []epistemics.ClaimID, evidenceRefs []epistemics.EvidenceRef, observedState epistemics.WorldOutcomeState, confidence, assessedAt int64) (epistemics.WorldOutcomeAssessment, error) {
if principalID == "" || attemptRef == "" || expectedEffect == "" || assessedAt < 1 || confidence < 0 || confidence > 1000 {
return epistemics.WorldOutcomeAssessment{}, ErrInvalidOutcomeAssessment
}
state := epistemics.OutcomeUnknownState
if len(observationRefs) == 0 {
state = epistemics.OutcomeUnknownState
} else if observedState == epistemics.OutcomeVerifiedSuccess || observedState == epistemics.OutcomeVerifiedPartial || observedState == epistemics.OutcomeVerifiedFailure || observedState == epistemics.OutcomeConflicted {
state = observedState
} else {
state = epistemics.OutcomeVerifiedPartial
}
id, err := ids.New()
if err != nil {
return epistemics.WorldOutcomeAssessment{}, err
}
value := epistemics.WorldOutcomeAssessment{ID: string(id), PrincipalID: principalID, ActionAttemptRef: attemptRef, ExecutionReceiptRefs: append([]string(nil), receiptRefs...), ExpectedEffectRef: expectedEffect, ObservationRefs: append([]epistemics.ObservationID(nil), observationRefs...), ClaimRefs: append([]epistemics.ClaimID(nil), claimRefs...), State: state, ConfidenceMillis: confidence, EvidenceRefs: append([]epistemics.EvidenceRef(nil), evidenceRefs...), AssessedAt: assessedAt}
if !value.Valid() {
return epistemics.WorldOutcomeAssessment{}, ErrInvalidOutcomeAssessment
}
return value, nil
}
+21
View File
@@ -0,0 +1,21 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/modules/epistemics/domain"
"testing"
)
func TestExecutionReceiptWithoutObservationRemainsUnknown(t *testing.T) {
value, err := domain.AssessWorldOutcome("principal", "attempt", "effect", []string{"receipt"}, nil, nil, nil, epistemics.OutcomeVerifiedSuccess, 1000, 1)
if err != nil || value.State != epistemics.OutcomeUnknownState {
t.Fatalf("value=%+v err=%v", value, err)
}
}
func TestObservedOutcomeCanBeVerifiedSeparately(t *testing.T) {
value, err := domain.AssessWorldOutcome("principal", "attempt", "effect", []string{"receipt"}, []epistemics.ObservationID{"observation"}, []epistemics.ClaimID{"claim"}, []epistemics.EvidenceRef{"evidence"}, epistemics.OutcomeVerifiedSuccess, 900, 1)
if err != nil || value.State != epistemics.OutcomeVerifiedSuccess || len(value.EvidenceRefs) != 1 {
t.Fatalf("value=%+v err=%v", value, err)
}
}
+14
View File
@@ -0,0 +1,14 @@
package domain
import "git.cin.su/m/Assistant/contracts/epistemics"
func AssessSourceReliability(sourceRef, domainRef string, freshness epistemics.FreshnessState, historyScore, priorScore int64, evidence []string, at int64) epistemics.SourceReliabilityAssessment {
score := (historyScore + priorScore) / 2
state := epistemics.ReliabilityCurrent
if freshness == epistemics.FreshnessUnknown {
state = epistemics.ReliabilityUnknown
} else if freshness == epistemics.FreshnessStale {
state = epistemics.ReliabilityAging
}
return epistemics.SourceReliabilityAssessment{SourceRef: sourceRef, DomainRef: domainRef, Freshness: freshness, HistoryScoreMillis: historyScore, ReliabilityScoreMillis: score, State: state, EvidenceRefs: append([]string(nil), evidence...), AssessedAtUnixMillis: at}
}
@@ -0,0 +1,14 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/modules/epistemics/domain"
"testing"
)
func TestSourceReliabilityIncludesDomainFreshnessAndHistory(t *testing.T) {
a := domain.AssessSourceReliability("source", "weather", epistemics.FreshnessStale, 900, 700, []string{"history"}, 1)
if !a.Valid() || a.State != epistemics.ReliabilityAging || a.ReliabilityScoreMillis != 800 {
t.Fatalf("assessment=%+v", a)
}
}
+36
View File
@@ -0,0 +1,36 @@
package domain
import (
"errors"
"git.cin.su/m/Assistant/contracts/identity"
)
var ErrInvalidRealm = errors.New("invalid principal data realm")
func ValidatePrincipalDataRealm(value identity.PrincipalDataRealm) error {
if !value.Valid() {
return ErrInvalidRealm
}
if value.Kind == identity.DataRealmPersonal && len(value.MemberPrincipalIDs) != 0 {
return ErrInvalidRealm
}
return nil
}
func CanReadRealm(value identity.PrincipalDataRealm, principalID identity.PrincipalID) bool {
if ValidatePrincipalDataRealm(value) != nil || principalID == "" {
return false
}
if value.Kind == identity.DataRealmPublic {
return true
}
if principalID == value.OwnerPrincipalID {
return true
}
for _, member := range value.MemberPrincipalIDs {
if member == principalID {
return value.Kind == identity.DataRealmShared && value.Shared
}
}
return false
}
+14
View File
@@ -0,0 +1,14 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/identity"
"git.cin.su/m/Assistant/modules/identity/domain"
"testing"
)
func TestRealmSeparatesOwnerSharedAndPublicAccess(t *testing.T) {
r := identity.PrincipalDataRealm{ID: "realm", OwnerPrincipalID: "owner", Kind: identity.DataRealmShared, Shared: true, MemberPrincipalIDs: []identity.PrincipalID{"member"}, Revision: 1, RecordedAtUnixMillis: 1}
if !domain.CanReadRealm(r, "owner") || !domain.CanReadRealm(r, "member") || domain.CanReadRealm(r, "guest") {
t.Fatalf("realm access leaked: %+v", r)
}
}
@@ -0,0 +1,31 @@
package domain
import (
"git.cin.su/m/Assistant/contracts/interaction"
"strings"
)
// ParseConfigurationCommand recognises bounded human intent and never writes
// configuration or invokes Authority/Commit.
func ParseConfigurationCommand(message, principalID, sourceRef string) interaction.ConfigurationCommand {
text := strings.TrimSpace(strings.ToLower(message))
if principalID == "" || sourceRef == "" {
return interaction.ConfigurationCommand{}
}
if strings.Contains(text, "какая настройка") || strings.HasPrefix(text, "какое значение") {
return interaction.ConfigurationCommand{Kind: interaction.ConfigurationCommandQuery, PrincipalID: principalID, SourceRef: sourceRef}
}
temporary := strings.Contains(text, "только сейчас") || strings.Contains(text, "на этот раз") || strings.Contains(text, "временно")
if strings.Contains(text, "настрой") || strings.Contains(text, "установи") || strings.Contains(text, "сделай") {
parts := strings.SplitN(message, "=", 2)
if len(parts) == 2 {
key := strings.TrimSpace(strings.TrimPrefix(strings.ToLower(parts[0]), "настройка"))
value := strings.TrimSpace(parts[1])
for _, marker := range []string{"только сейчас", "на этот раз", "временно"} {
value = strings.TrimSpace(strings.ReplaceAll(strings.ToLower(value), marker, ""))
}
return interaction.ConfigurationCommand{Kind: interaction.ConfigurationCommandSet, PrincipalID: principalID, DefinitionRef: key, TypedValue: value, TemporaryOverride: temporary, SourceRef: sourceRef}
}
}
return interaction.ConfigurationCommand{}
}
@@ -0,0 +1,14 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/interaction"
interactiondomain "git.cin.su/m/Assistant/modules/interaction/domain"
"testing"
)
func TestConversationParserProducesIntentOnly(t *testing.T) {
value := interactiondomain.ParseConfigurationCommand("Настройка language = ru только сейчас", "principal-1", "utterance-1")
if value.Kind != interaction.ConfigurationCommandSet || value.DefinitionRef != "language" || value.TypedValue != "ru" || !value.TemporaryOverride {
t.Fatalf("value=%+v", value)
}
}
@@ -0,0 +1,19 @@
package domain
import "git.cin.su/m/Assistant/contracts/interaction"
type ContextProjection struct {
Text string
Source string
UsedPersonalMemoryFallback bool
}
// BuildGen2Context is a read-side projection over canonical utterance history.
// PersonalMemory remains a compatibility fallback and is never written here.
func BuildGen2Context(history []interaction.HumanUtterance) ContextProjection {
text := CompilePersonalMemory(history).ContextText()
if text != "" {
return ContextProjection{Text: text, Source: "retrieval:interaction-utterances"}
}
return ContextProjection{Text: text, Source: "personal-memory-v1-fallback", UsedPersonalMemoryFallback: true}
}
@@ -0,0 +1,18 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/interaction"
"git.cin.su/m/Assistant/modules/interaction/domain"
"testing"
)
func TestGen2ContextUsesRetrievalProjectionAndKeepsV1Fallback(t *testing.T) {
got := domain.BuildGen2Context([]interaction.HumanUtterance{{ID: "u", Content: "Я сейчас в Москве", ReceivedAtUnixMillis: 1}})
if got.Source != "retrieval:interaction-utterances" || got.UsedPersonalMemoryFallback {
t.Fatalf("got %#v", got)
}
empty := domain.BuildGen2Context(nil)
if !empty.UsedPersonalMemoryFallback {
t.Fatalf("fallback missing: %#v", empty)
}
}
+12
View File
@@ -0,0 +1,12 @@
package domain
import "git.cin.su/m/Assistant/contracts/interaction"
// AttributeSpeaker is an observational hint only. It deliberately cannot
// manufacture an authenticated principal binding from voice recognition.
func AttributeSpeaker(sourceRef, principalCandidate, observationRef string, confidence int64) interaction.SpeakerAttribution {
if sourceRef == "" || observationRef == "" || confidence < 0 || confidence > 1000 {
return interaction.SpeakerAttribution{}
}
return interaction.SpeakerAttribution{SourceRef: sourceRef, PrincipalCandidate: principalCandidate, ConfidenceMillis: confidence, ObservationRef: observationRef, Authenticated: false}
}
@@ -0,0 +1,13 @@
package domain_test
import (
"git.cin.su/m/Assistant/modules/interaction/domain"
"testing"
)
func TestSpeakerRecognitionRemainsObservationNotAuthentication(t *testing.T) {
a := domain.AttributeSpeaker("mic-1", "principal-member", "observation-1", 700)
if a.Authenticated || a.PrincipalCandidate == "" || a.ObservationRef == "" {
t.Fatalf("attribution=%+v", a)
}
}
+17
View File
@@ -0,0 +1,17 @@
package domain_test
import (
selfcontract "git.cin.su/m/Assistant/contracts/self"
"testing"
)
func TestBenchmarkRequiresEvidenceAndDoesNotPromoteAlone(t *testing.T) {
e := selfcontract.BenchmarkEvaluation{CaseRef: "case", QualityMillis: 900}
if e.Valid() {
t.Fatal("benchmark without evidence accepted")
}
e.EvidenceRefs = []selfcontract.SemanticReference{{OwnerNamespace: "epistemics", SemanticKind: "evaluation", StableID: "e"}}
if !e.Valid() {
t.Fatal("evidence-backed evaluation rejected")
}
}
+8
View File
@@ -0,0 +1,8 @@
package domain
import (
"git.cin.su/m/Assistant/contracts/self"
)
func ValidateCompetence(v self.CompetenceAssessment) error { return v.Validate() }
func ValidateLearning(v self.LearningLedgerEntry) error { return v.Validate() }
+18
View File
@@ -0,0 +1,18 @@
package domain_test
import (
selfcontract "git.cin.su/m/Assistant/contracts/self"
"git.cin.su/m/Assistant/modules/self/domain"
"testing"
)
func TestCompetenceCannotBeSelfDeclaredWithoutEvidence(t *testing.T) {
v := selfcontract.CompetenceAssessment{ID: "a", PrincipalID: "p", SubjectRef: selfcontract.SemanticReference{OwnerNamespace: "capability", SemanticKind: "skill", StableID: "s"}, Revision: 1, ConfidenceMillis: 1000, AssessedAt: 1}
if domain.ValidateCompetence(v) == nil {
t.Fatal("unsupported competence accepted")
}
v.EvidenceRefs = []selfcontract.SemanticReference{{OwnerNamespace: "epistemics", SemanticKind: "evaluation", StableID: "e"}}
if err := domain.ValidateCompetence(v); err != nil {
t.Fatal(err)
}
}
+86
View File
@@ -0,0 +1,86 @@
package domain
import (
"fmt"
contract "git.cin.su/m/Assistant/contracts/situation"
)
// FocusStack is a rebuildable, situation-owned projection. Push suspends the
// previous active frame; Pop resumes its parent and never deletes a frame.
type FocusStack struct{ frames []contract.FocusFrame }
func NewFocusStack(frames []contract.FocusFrame) (FocusStack, error) {
stack := FocusStack{frames: append([]contract.FocusFrame(nil), frames...)}
for _, frame := range stack.frames {
if err := frame.Validate(); err != nil {
return FocusStack{}, err
}
}
return stack, nil
}
func (s FocusStack) Frames() []contract.FocusFrame {
return append([]contract.FocusFrame(nil), s.frames...)
}
func (s FocusStack) Current() (contract.FocusFrame, error) {
for i := len(s.frames) - 1; i >= 0; i-- {
if s.frames[i].State == contract.FocusActive {
return s.frames[i], nil
}
}
return contract.FocusFrame{}, ErrNoActiveFocus
}
func (s FocusStack) Push(frame contract.FocusFrame) (FocusStack, error) {
if err := frame.Validate(); err != nil {
return FocusStack{}, err
}
if frame.State != contract.FocusActive {
return FocusStack{}, fmt.Errorf("pushed frame must be active")
}
frames := s.Frames()
if len(frames) > 0 {
current, err := s.Current()
if err == nil {
for i := range frames {
if frames[i].ID == current.ID {
frames[i].State = contract.FocusSuspended
break
}
}
frame.ParentFrameRef = &current.ID
}
}
frames = append(frames, frame)
return FocusStack{frames: frames}, nil
}
func (s FocusStack) Pop() (FocusStack, contract.FocusFrame, error) {
current, err := s.Current()
if err != nil {
return FocusStack{}, contract.FocusFrame{}, err
}
frames := s.Frames()
for i := range frames {
if frames[i].ID == current.ID {
frames[i].State = contract.FocusSuspended
break
}
}
if current.ParentFrameRef != nil {
for i := range frames {
if frames[i].ID == *current.ParentFrameRef {
frames[i].State = contract.FocusActive
break
}
}
}
return FocusStack{frames: frames}, current, nil
}
// ProjectFocusProjection retains the V1 API as a read projection only.
func ProjectFocusProjection(frame contract.FocusFrame, project contract.ProjectDescriptor) contract.ActiveProjectFocus {
return contract.ActiveProjectFocus{ActorID: frame.ActorID, PrincipalID: frame.PrincipalID, ProjectID: contract.ProjectID(project.ID), ProjectDisplayName: project.DisplayName, Provenance: contract.ProjectResolutionProvenance(frame.Provenance), ConfidenceMillis: frame.ConfidenceMillis, SourceUtteranceID: frame.SourceUtteranceRef, UpdatedAtUnixMillis: int64(frame.RecordedAt)}
}
+36
View File
@@ -0,0 +1,36 @@
package domain_test
import (
"testing"
contract "git.cin.su/m/Assistant/contracts/situation"
"git.cin.su/m/Assistant/modules/situation/domain"
)
func TestFocusStackPushPopKeepsParentAndSeparatesCompanies(t *testing.T) {
base := contract.FocusFrame{ID: "company-a", PrincipalID: "principal-a", ActorID: "actor", Revision: 1, ContextScopeRef: contract.SemanticReference{OwnerNamespace: "situation", SemanticKind: "context_scope", StableID: "scope-a"}, State: contract.FocusActive, Provenance: contract.FocusExplicitHuman, RecordedAt: 1}
stack, err := domain.NewFocusStack([]contract.FocusFrame{base})
if err != nil {
t.Fatal(err)
}
child := base
child.ID = "company-b"
child.PrincipalID = "principal-b"
child.ContextScopeRef.StableID = "scope-b"
stack, err = stack.Push(child)
if err != nil {
t.Fatal(err)
}
current, _ := stack.Current()
if current.ID != "company-b" || current.ParentFrameRef == nil || *current.ParentFrameRef != "company-a" {
t.Fatalf("unexpected current %#v", current)
}
stack, _, err = stack.Pop()
if err != nil {
t.Fatal(err)
}
current, _ = stack.Current()
if current.ID != "company-a" {
t.Fatalf("parent was not resumed: %#v", current)
}
}
+14
View File
@@ -0,0 +1,14 @@
package domain
import "git.cin.su/m/Assistant/contracts/work"
func AssessConsequences(id string, target string, impact, reversibility, uncertainty, recoverability, cost int64, at int64) work.ConsequenceAssessment {
a := work.ConsequenceAssessment{ID: id, TargetRefs: []string{target}, Impact: impact, Reversibility: reversibility, Uncertainty: uncertainty, Recoverability: recoverability, CostOfError: cost, RecordedAtUnixMillis: at}
a.RequiresDryRun = impact >= 700 || reversibility >= 700
a.RequiresBackup = reversibility >= 500
a.RecommendedConfirmation = "STANDARD"
if uncertainty*cost > 500000 {
a.RecommendedConfirmation = "EXPLICIT_OWNER_CONFIRMATION"
}
return a
}
+13
View File
@@ -0,0 +1,13 @@
package domain_test
import (
"git.cin.su/m/Assistant/modules/work/domain"
"testing"
)
func TestConsequenceAdvisesMitigationWithoutCapabilityBlacklist(t *testing.T) {
a := domain.AssessConsequences("a", "database:a", 800, 800, 900, 300, 900, 1)
if !a.Valid() || !a.RequiresDryRun || !a.RequiresBackup || a.RecommendedConfirmation != "EXPLICIT_OWNER_CONFIRMATION" {
t.Fatalf("%#v", a)
}
}
+76
View File
@@ -0,0 +1,76 @@
package domain
import (
"errors"
"git.cin.su/m/Assistant/contracts/work"
)
var ErrGovernedEvolution = errors.New("governed evolution gate failed")
func RunGovernedEvolution(needRef string, ops work.GovernedEvolutionOps) (work.GovernedEvolutionResult, error) {
result := work.GovernedEvolutionResult{NeedRef: needRef, Stages: []work.EvolutionRunStage{work.EvolutionNeedRecorded}}
if needRef == "" || ops.CreateCandidate == nil || ops.Evaluate == nil || ops.SandboxBuild == nil || ops.Benchmark == nil || ops.Promote == nil || ops.Rollback == nil || ops.LearningLedgerOutcome == nil {
return result, ErrGovernedEvolution
}
candidate, err := ops.CreateCandidate()
if err != nil {
return result, err
}
if candidate.ID == "" || candidate.ProposalRef == "" {
return result, ErrGovernedEvolution
}
result.CandidateRef = candidate.ID
result.Stages = append(result.Stages, work.EvolutionCandidateBuilt)
evaluation, err := ops.Evaluate(candidate)
if err != nil || !evaluation.ValidFor(candidate) {
return result, ErrGovernedEvolution
}
result.EvaluationRef = evaluation.CandidateRef
result.Stages = append(result.Stages, work.EvolutionIndependentlyEvaluated)
sandboxEvidence, err := ops.SandboxBuild(candidate)
if err != nil || sandboxEvidence == "" {
return result, ErrGovernedEvolution
}
candidate.SandboxEvidenceRefs = append(candidate.SandboxEvidenceRefs, sandboxEvidence)
result.EvidenceRefs = append(result.EvidenceRefs, sandboxEvidence)
result.Stages = append(result.Stages, work.EvolutionSandboxed)
benchmarkEvidence, passed, err := ops.Benchmark(candidate)
if err != nil || !passed || benchmarkEvidence == "" {
result = rollbackEvolution(result, candidate, ops)
return result, ErrGovernedEvolution
}
candidate.BenchmarkEvidenceRefs = append(candidate.BenchmarkEvidenceRefs, benchmarkEvidence)
result.EvidenceRefs = append(result.EvidenceRefs, benchmarkEvidence)
result.Stages = append(result.Stages, work.EvolutionBenchmarked)
if ops.Canary != nil {
canaryEvidence, passed, canaryErr := ops.Canary(candidate)
if canaryErr != nil || !passed || canaryEvidence == "" {
result = rollbackEvolution(result, candidate, ops)
return result, ErrGovernedEvolution
}
result.EvidenceRefs = append(result.EvidenceRefs, canaryEvidence)
result.Stages = append(result.Stages, work.EvolutionCanaried)
}
promotionRef, err := ops.Promote(candidate, evaluation)
if err != nil || promotionRef == "" {
result = rollbackEvolution(result, candidate, ops)
return result, ErrGovernedEvolution
}
result.Promoted = true
result.Stages = append(result.Stages, work.EvolutionPromoted)
result.LearningLedgerOutcomeRef, err = ops.LearningLedgerOutcome(result)
if err != nil || result.LearningLedgerOutcomeRef == "" {
return result, ErrGovernedEvolution
}
return result, nil
}
func rollbackEvolution(result work.GovernedEvolutionResult, candidate work.EvolutionCandidate, ops work.GovernedEvolutionOps) work.GovernedEvolutionResult {
ref, err := ops.Rollback(candidate)
if err == nil && ref != "" {
result.RollbackRef = ref
result.Stages = append(result.Stages, work.EvolutionRolledBack)
result.LearningLedgerOutcomeRef, _ = ops.LearningLedgerOutcome(result)
}
return result
}
@@ -0,0 +1,77 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/work"
"git.cin.su/m/Assistant/modules/work/domain"
"testing"
)
func TestGovernedEvolutionExecutesGatesAndLedgerOutcome(t *testing.T) {
calls := []string{}
result, err := domain.RunGovernedEvolution("need-1", work.GovernedEvolutionOps{
CreateCandidate: func() (work.EvolutionCandidate, error) {
calls = append(calls, "candidate")
return work.EvolutionCandidate{ID: "candidate-1", ProposalRef: "proposal-1", CreatorIdentity: "creator", RollbackRef: "rollback-plan"}, nil
},
Evaluate: func(c work.EvolutionCandidate) (work.EvolutionEvaluation, error) {
calls = append(calls, "evaluate")
return work.EvolutionEvaluation{CandidateRef: c.ID, EvaluatorIdentity: "independent", Approved: true, MustNotWorsenPassed: true, EvidenceRefs: []work.EvidenceRef{"eval"}, RecordedAtUnixMillis: 1}, nil
},
SandboxBuild: func(work.EvolutionCandidate) (work.EvidenceRef, error) {
calls = append(calls, "sandbox-build")
return "sandbox", nil
},
Benchmark: func(work.EvolutionCandidate) (work.EvidenceRef, bool, error) {
calls = append(calls, "benchmark")
return "benchmark", true, nil
},
Canary: func(work.EvolutionCandidate) (work.EvidenceRef, bool, error) {
calls = append(calls, "canary")
return "canary", true, nil
},
Promote: func(work.EvolutionCandidate, work.EvolutionEvaluation) (string, error) {
calls = append(calls, "promote")
return "promotion", nil
},
Rollback: func(work.EvolutionCandidate) (string, error) {
calls = append(calls, "rollback")
return "rollback", nil
},
LearningLedgerOutcome: func(work.GovernedEvolutionResult) (string, error) {
calls = append(calls, "ledger")
return "ledger-outcome", nil
},
})
if err != nil || !result.Promoted || result.LearningLedgerOutcomeRef != "ledger-outcome" {
t.Fatalf("result=%+v err=%v", result, err)
}
want := []string{"candidate", "evaluate", "sandbox-build", "benchmark", "canary", "promote", "ledger"}
if len(calls) != len(want) {
t.Fatalf("calls=%v", calls)
}
for i := range want {
if calls[i] != want[i] {
t.Fatalf("calls=%v", calls)
}
}
}
func TestGovernedEvolutionRollsBackOnMustNotWorsenFailure(t *testing.T) {
rolledBack := false
result, err := domain.RunGovernedEvolution("need-1", work.GovernedEvolutionOps{
CreateCandidate: func() (work.EvolutionCandidate, error) {
return work.EvolutionCandidate{ID: "candidate-1", ProposalRef: "proposal-1", CreatorIdentity: "creator", RollbackRef: "rollback-plan"}, nil
},
Evaluate: func(c work.EvolutionCandidate) (work.EvolutionEvaluation, error) {
return work.EvolutionEvaluation{CandidateRef: c.ID, EvaluatorIdentity: "independent", Approved: true, MustNotWorsenPassed: true, EvidenceRefs: []work.EvidenceRef{"eval"}, RecordedAtUnixMillis: 1}, nil
},
SandboxBuild: func(work.EvolutionCandidate) (work.EvidenceRef, error) { return "sandbox", nil }, Benchmark: func(work.EvolutionCandidate) (work.EvidenceRef, bool, error) { return "benchmark", false, nil },
Promote: func(work.EvolutionCandidate, work.EvolutionEvaluation) (string, error) {
t.Fatal("promotion bypassed failed benchmark")
return "", nil
}, Rollback: func(work.EvolutionCandidate) (string, error) { rolledBack = true; return "rollback-evidence", nil }, LearningLedgerOutcome: func(r work.GovernedEvolutionResult) (string, error) { return "ledger-rollback", nil },
})
if err == nil || !rolledBack || result.RollbackRef != "rollback-evidence" || result.Promoted {
t.Fatalf("result=%+v err=%v", result, err)
}
}
+18
View File
@@ -0,0 +1,18 @@
package domain
import "git.cin.su/m/Assistant/contracts/work"
func PauseInvestigation(value work.Investigation) work.Investigation {
if value.Valid() {
value.State = work.LongRunningPaused
value.Revision++
}
return value
}
func ResumeInvestigation(value work.Investigation) work.Investigation {
if value.Valid() && value.State == work.LongRunningPaused {
value.State = work.LongRunningRunning
value.Revision++
}
return value
}
+16
View File
@@ -0,0 +1,16 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/work"
"git.cin.su/m/Assistant/modules/work/domain"
"testing"
)
func TestInvestigationPauseResumeIsDurableStateTransition(t *testing.T) {
w := work.Investigation{ID: "i", Objective: "diagnose", State: work.LongRunningRunning, Revision: 1, RecordedAtUnixMillis: 1}
w = domain.PauseInvestigation(w)
w = domain.ResumeInvestigation(w)
if w.State != work.LongRunningRunning || w.Revision != 3 {
t.Fatalf("%#v", w)
}
}
+17
View File
@@ -0,0 +1,17 @@
package domain
import "git.cin.su/m/Assistant/contracts/work"
func AssembleSpecialists(p work.PerspectiveSpec, subtasks []string) work.TeamDecision {
if !p.Valid() {
return work.TeamDecision{Reason: "invalid perspective"}
}
if len(subtasks) < 2 {
return work.TeamDecision{Reason: "single reasoning path is sufficient"}
}
assignments := make([]work.SpecialistAssignment, 0, len(subtasks))
for _, s := range subtasks {
assignments = append(assignments, work.SpecialistAssignment{Perspective: p, SubtaskRef: s, FocusRef: p.FocusRef, SkillRefs: append([]string(nil), p.SkillRefs...), ToolRefs: append([]string(nil), p.ToolRefs...)})
}
return work.TeamDecision{UseTeam: true, Reason: "independent subtasks justify bounded perspectives", Assignments: assignments}
}
+17
View File
@@ -0,0 +1,17 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/work"
"git.cin.su/m/Assistant/modules/work/domain"
"testing"
)
func TestPerspectiveTeamIsBoundedByIndependentSubtasks(t *testing.T) {
p := work.PerspectiveSpec{ID: "architect", ObjectiveLens: "architecture", FocusRef: "focus-1", SkillRefs: []string{"skill-1"}, ToolRefs: []string{"tool-1"}, EvaluationCriteria: []string{"correctness"}, ExpectedOutputShape: "finding"}
if d := domain.AssembleSpecialists(p, []string{"a"}); d.UseTeam {
t.Fatal("team for one subtask")
}
if d := domain.AssembleSpecialists(p, []string{"a", "b"}); !d.UseTeam || len(d.Assignments) != 2 {
t.Fatalf("%#v", d)
}
}
+7
View File
@@ -0,0 +1,7 @@
package domain
import "git.cin.su/m/Assistant/contracts/work"
func PromoteEvolution(c work.EvolutionCandidate, e work.EvolutionEvaluation) bool {
return e.ValidFor(c) && c.ProposalRef != "" && c.RollbackRef != "" && len(c.SandboxEvidenceRefs) > 0 && len(c.BenchmarkEvidenceRefs) > 0
}
@@ -0,0 +1,19 @@
package domain_test
import (
"git.cin.su/m/Assistant/contracts/work"
"git.cin.su/m/Assistant/modules/work/domain"
"testing"
)
func TestEvolutionRequiresIndependentEvaluatorAndRollbackEvidence(t *testing.T) {
c := work.EvolutionCandidate{ID: "c", ProposalRef: "p", ChangeLevel: work.EvolutionBehavior, CreatorIdentity: "creator", RollbackRef: "rollback", SandboxEvidenceRefs: []work.EvidenceRef{"sandbox"}, BenchmarkEvidenceRefs: []work.EvidenceRef{"benchmark"}}
e := work.EvolutionEvaluation{CandidateRef: "c", EvaluatorIdentity: "creator", Approved: true, MustNotWorsenPassed: true, EvidenceRefs: []work.EvidenceRef{"eval"}, RecordedAtUnixMillis: 1}
if domain.PromoteEvolution(c, e) {
t.Fatal("creator promoted own change")
}
e.EvaluatorIdentity = "independent"
if !domain.PromoteEvolution(c, e) {
t.Fatal("independently evaluated candidate rejected")
}
}
+8
View File
@@ -0,0 +1,8 @@
# world
World owns typed referents, vocabulary and identity-resolution lineage. It
does not own observations, claims, beliefs, or factual values about a
referent. Those remain Epistemics-owned evidence.
World domain code does not import adapters, runtime or provider packages and
does not write another owner's canonical state.
+30
View File
@@ -0,0 +1,30 @@
package domain_test
import (
"testing"
"git.cin.su/m/Assistant/contracts/world"
"git.cin.su/m/Assistant/modules/world/domain"
)
func TestResolveCandidatesDoesNotAutoMergeAmbiguousPeopleOrSystems(t *testing.T) {
decision, candidates := domain.ResolveCandidates([]world.IdentityResolutionCandidate{
{ObjectRef: world.SemanticReference{OwnerNamespace: "world", SemanticKind: "person", StableID: "ivan-telegram"}, Confidence: 800},
{ObjectRef: world.SemanticReference{OwnerNamespace: "world", SemanticKind: "person", StableID: "ivan-crm"}, Confidence: 800},
}, 700)
if decision != world.ResolutionUnresolved || len(candidates) != 2 {
t.Fatalf("ambiguous result = %s, %#v", decision, candidates)
}
}
func TestVersionAndEnvironmentReferencesAreTyped(t *testing.T) {
version := world.SemanticReference{OwnerNamespace: "world", SemanticKind: "version", StableID: "unf-3"}
binding := world.VersionBinding{SubjectRef: world.SemanticReference{OwnerNamespace: "world", SemanticKind: "database", StableID: "company-a-unf"}, VersionRef: version, MatchMode: world.VersionExact}
if err := binding.Validate(); err != nil {
t.Fatal(err)
}
environment := world.EnvironmentReference{EnvironmentRef: world.SemanticReference{OwnerNamespace: "world", SemanticKind: "environment", StableID: "company-a-prod"}, VersionRef: &version}
if err := environment.Validate(); err != nil {
t.Fatal(err)
}
}
+34
View File
@@ -0,0 +1,34 @@
package domain
import "git.cin.su/m/Assistant/contracts/world"
import "sort"
func ValidateObject(value world.WorldObject) error { return value.Validate() }
func ValidateKindDefinition(value world.WorldObjectKindDefinition) error { return value.Validate() }
func ValidateAlias(value world.WorldAlias) error { return value.Validate() }
func ValidateFacetDefinition(value world.FacetDefinition) error { return value.Validate() }
func ValidateRelationDefinition(value world.RelationDefinition) error { return value.Validate() }
func ValidateResolution(value world.IdentityResolutionDecisionRecord) error { return value.Validate() }
func ValidateLineage(value world.WorldLineage) error { return value.Validate() }
// ResolveCandidates deliberately refuses to merge an ambiguous result. A
// caller may persist the returned UNRESOLVED decision and later re-evaluate it
// with additional evidence.
func ResolveCandidates(candidates []world.IdentityResolutionCandidate, minimumConfidence int64) (world.ResolutionDecision, []world.IdentityResolutionCandidate) {
ordered := append([]world.IdentityResolutionCandidate(nil), candidates...)
sort.SliceStable(ordered, func(i, j int) bool { return ordered[i].Confidence > ordered[j].Confidence })
if len(ordered) == 0 || ordered[0].Confidence < minimumConfidence {
return world.ResolutionUnresolved, ordered
}
if len(ordered) > 1 && ordered[0].Confidence == ordered[1].Confidence {
return world.ResolutionUnresolved, ordered
}
return world.ResolutionSame, ordered[:1]
}
+17
View File
@@ -0,0 +1,17 @@
package ports
import (
"context"
"git.cin.su/m/Assistant/contracts/world"
)
type Repository interface {
SaveKindDefinition(context.Context, world.WorldObjectKindDefinition) error
SaveObject(context.Context, world.WorldObject) error
SaveAlias(context.Context, world.WorldAlias) error
SaveFacetDefinition(context.Context, world.FacetDefinition) error
SaveRelationDefinition(context.Context, world.RelationDefinition) error
SaveResolution(context.Context, world.IdentityResolutionDecisionRecord) error
SaveLineage(context.Context, world.WorldLineage) error
}
+14
View File
@@ -0,0 +1,14 @@
package clock
import "time"
// Instant is a UTC point represented as Unix milliseconds.
type Instant int64
func (i Instant) Valid() bool { return i > 0 }
func NowInstant() Instant { return FromTime(time.Now().UTC()) }
func FromTime(value time.Time) Instant { return Instant(value.UTC().UnixMilli()) }
func (i Instant) Time() time.Time { return time.UnixMilli(int64(i)).UTC() }
+14
View File
@@ -0,0 +1,14 @@
package clock
import (
"testing"
"time"
)
func TestInstantRoundTripUsesUTCUnixMilliseconds(t *testing.T) {
want := time.Date(2026, time.August, 29, 12, 34, 56, 789000000, time.FixedZone("local", 3*60*60))
got := FromTime(want).Time()
if !got.Equal(want.UTC()) || got.Location() != time.UTC {
t.Fatalf("instant round trip = %v, want %v UTC", got, want.UTC())
}
}
+34 -5
View File
@@ -6,14 +6,43 @@ import (
"fmt"
)
// ID is a transport-neutral opaque identifier primitive. Domain packages wrap it
// in strong semantic ID types; do not pass bare ID across semantic boundaries.
type ID string
// StableID is a transport-neutral opaque identifier primitive. Domain packages
// wrap it in strong semantic ID types; do not pass bare StableID across
// semantic boundaries.
type StableID string
func New() (ID, error) {
// ID is retained as a compatibility name for the V1 primitive.
type ID = StableID
// Revision is the optimistic version of a versioned semantic record.
type Revision uint64
const InitialRevision Revision = 1
func (r Revision) Valid() bool { return r >= InitialRevision }
// SemanticRef is a technical cross-owner reference envelope. It identifies a
// record but does not grant storage ownership or provide generic CRUD.
type SemanticRef struct {
OwnerNamespace string
SemanticKind string
StableID StableID
Revision *Revision
}
func (r SemanticRef) Valid() bool {
return r.OwnerNamespace != "" && r.SemanticKind != "" && r.StableID != "" &&
(r.Revision == nil || r.Revision.Valid())
}
func NewStableID() (StableID, error) {
var b [16]byte
if _, err := rand.Read(b[:]); err != nil {
return "", fmt.Errorf("generate id: %w", err)
}
return ID(hex.EncodeToString(b[:])), nil
return StableID(hex.EncodeToString(b[:])), nil
}
func New() (ID, error) {
return NewStableID()
}
+21
View File
@@ -0,0 +1,21 @@
package ids
import "testing"
func TestNewStableIDIsOpaque128BitHex(t *testing.T) {
id, err := NewStableID()
if err != nil || len(id) != 32 {
t.Fatalf("NewStableID() = %q, %v", id, err)
}
if !(SemanticRef{OwnerNamespace: "world", SemanticKind: "object", StableID: id}.Valid()) {
t.Fatal("stable id was not accepted by semantic reference")
}
}
func TestSemanticRefRejectsInvalidRevision(t *testing.T) {
revision := Revision(0)
ref := SemanticRef{OwnerNamespace: "world", SemanticKind: "object", StableID: "id", Revision: &revision}
if ref.Valid() {
t.Fatal("semantic reference accepted invalid revision")
}
}
+7
View File
@@ -0,0 +1,7 @@
package secrets
import "git.cin.su/m/Assistant/contracts/configuration"
func ValidateBootstrap(value configuration.BootstrapConfig) bool {
return value.NodeIdentity != "" && value.ControlDatabaseLocator != "" && value.RootSecretResolverLocator != ""
}
+92
View File
@@ -0,0 +1,92 @@
package retrieval
import "sort"
type Lane string
const (
LaneSemantic Lane = "SEMANTIC"
LaneEntity Lane = "ENTITY"
LaneTemporal Lane = "TEMPORAL"
LaneGoal Lane = "GOAL"
LanePositiveExperience Lane = "POSITIVE_EXPERIENCE"
LaneNegativeExperience Lane = "NEGATIVE_EXPERIENCE"
LaneContradiction Lane = "CONTRADICTION"
LaneSkill Lane = "SKILL"
)
// RetrievalDocument is disposable read-side projection data. SourceRef and
// Owner preserve provenance; this type never becomes canonical meaning.
type RetrievalDocument struct {
ID string
SourceRef string
Owner string
PrincipalID string
ContextScopeRef string
VersionRef string
Lane Lane
Text string
Relevance int
Freshness int
Confidence int
Salience int
Cost int
}
type Query struct {
PrincipalID string
ContextScopeRef string
VersionRef string
Lanes []Lane
Limit int
}
func FilterAndRank(documents []RetrievalDocument, query Query) []RetrievalDocument {
filtered := make([]RetrievalDocument, 0, len(documents))
for _, doc := range documents {
if doc.PrincipalID != query.PrincipalID || (query.ContextScopeRef != "" && doc.ContextScopeRef != query.ContextScopeRef) || (query.VersionRef != "" && doc.VersionRef != query.VersionRef) || !containsLane(query.Lanes, doc.Lane) {
continue
}
filtered = append(filtered, doc)
}
sort.SliceStable(filtered, func(i, j int) bool {
left := filtered[i].Relevance + filtered[i].Freshness + filtered[i].Confidence + filtered[i].Salience - filtered[i].Cost
right := filtered[j].Relevance + filtered[j].Freshness + filtered[j].Confidence + filtered[j].Salience - filtered[j].Cost
if left != right {
return left > right
}
return filtered[i].ID < filtered[j].ID
})
if query.Limit > 0 && len(filtered) > query.Limit {
filtered = filtered[:query.Limit]
}
return filtered
}
func containsLane(lanes []Lane, lane Lane) bool {
if len(lanes) == 0 {
return true
}
for _, v := range lanes {
if v == lane {
return true
}
}
return false
}
type ProjectionBuilder interface {
Build() ([]RetrievalDocument, error)
}
func Rebuild(builders ...ProjectionBuilder) ([]RetrievalDocument, error) {
var result []RetrievalDocument
for _, builder := range builders {
docs, err := builder.Build()
if err != nil {
return nil, err
}
result = append(result, docs...)
}
return result, nil
}
+14
View File
@@ -0,0 +1,14 @@
package retrieval_test
import (
"git.cin.su/m/Assistant/runtime/retrieval"
"testing"
)
func TestScopeAndVersionFilterBeforeRanking(t *testing.T) {
docs := []retrieval.RetrievalDocument{{ID: "wrong-company", PrincipalID: "a", ContextScopeRef: "b", VersionRef: "v", Lane: retrieval.LaneSemantic, Relevance: 100}, {ID: "right", PrincipalID: "a", ContextScopeRef: "a", VersionRef: "v", Lane: retrieval.LaneNegativeExperience, Relevance: 1}, {ID: "wrong-version", PrincipalID: "a", ContextScopeRef: "a", VersionRef: "old", Lane: retrieval.LaneSemantic, Relevance: 100}}
got := retrieval.FilterAndRank(docs, retrieval.Query{PrincipalID: "a", ContextScopeRef: "a", VersionRef: "v", Lanes: []retrieval.Lane{retrieval.LaneSemantic, retrieval.LaneNegativeExperience}, Limit: 10})
if len(got) != 1 || got[0].ID != "right" {
t.Fatalf("got %#v", got)
}
}
+94
View File
@@ -0,0 +1,94 @@
package supervisor
import (
"encoding/json"
"errors"
"os"
"path/filepath"
)
// DurableStore is supervisor-owned external control-plane state. It is not a
// candidate Assistant process-local recovery cache.
type DurableStore struct{ path string }
func NewDurableStore(path string) (*DurableStore, error) {
if path == "" || !filepath.IsAbs(path) {
return nil, errors.New("supervisor state path must be absolute")
}
return &DurableStore{path: path}, nil
}
func (s *DurableStore) Save(value Lifeboat) error {
if s == nil || s.path == "" {
return errors.New("supervisor state store is unavailable")
}
payload, err := json.Marshal(value)
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(s.path), 0700); err != nil {
return err
}
temporary, err := os.CreateTemp(filepath.Dir(s.path), ".lifeboat-*.tmp")
if err != nil {
return err
}
temporaryName := temporary.Name()
defer os.Remove(temporaryName)
if err = temporary.Chmod(0600); err == nil {
_, err = temporary.Write(payload)
}
if closeErr := temporary.Close(); err == nil {
err = closeErr
}
if err != nil {
return err
}
return os.Rename(temporaryName, s.path)
}
func (s *DurableStore) Load() (Lifeboat, error) {
if s == nil || s.path == "" {
return Lifeboat{}, errors.New("supervisor state store is unavailable")
}
payload, err := os.ReadFile(s.path)
if err != nil {
return Lifeboat{}, err
}
var value Lifeboat
if err := json.Unmarshal(payload, &value); err != nil {
return Lifeboat{}, err
}
return value, nil
}
// PersistentLifeboat reloads before every transition and commits after it.
type PersistentLifeboat struct{ store *DurableStore }
func NewPersistentLifeboat(store *DurableStore) *PersistentLifeboat {
return &PersistentLifeboat{store: store}
}
func (p *PersistentLifeboat) transition(fn func(*Lifeboat) bool) (bool, error) {
value, err := p.store.Load()
if err != nil && !os.IsNotExist(err) {
return false, err
}
ok := fn(&value)
if !ok {
return false, nil
}
if err := p.store.Save(value); err != nil {
return false, err
}
return true, nil
}
func (p *PersistentLifeboat) Start(candidate Release) (bool, error) {
return p.transition(func(value *Lifeboat) bool { return value.Start(candidate) })
}
func (p *PersistentLifeboat) Record(observation Observation) (bool, error) {
return p.transition(func(value *Lifeboat) bool { return value.Record(observation) })
}
func (p *PersistentLifeboat) Rollback() (bool, error) {
return p.transition(func(value *Lifeboat) bool { return value.Rollback() })
}
func (p *PersistentLifeboat) Snapshot() (Lifeboat, error) { return p.store.Load() }
+62
View File
@@ -0,0 +1,62 @@
package supervisor
type ReleaseState string
const (
ReleaseCandidate ReleaseState = "CANDIDATE"
ReleaseHealthy ReleaseState = "HEALTHY"
ReleaseFailed ReleaseState = "FAILED"
ReleaseRolledBack ReleaseState = "ROLLED_BACK"
)
type Release struct {
ID string
Version string
State ReleaseState
LastKnownGood bool
}
type Observation struct {
ReleaseID string
Ready bool
Reason string
ObservedAtUnixMillis int64
}
type Lifeboat struct {
Current Release
LastKnownGood Release
Observations []Observation
}
func (l *Lifeboat) Start(candidate Release) bool {
if candidate.ID == "" || candidate.Version == "" {
return false
}
candidate.State = ReleaseCandidate
l.Current = candidate
return true
}
func (l *Lifeboat) Record(o Observation) bool {
if o.ReleaseID == "" {
return false
}
l.Observations = append(l.Observations, o)
if o.ReleaseID != l.Current.ID {
return true
}
if o.Ready {
l.Current.State = ReleaseHealthy
l.Current.LastKnownGood = true
l.LastKnownGood = l.Current
} else {
l.Current.State = ReleaseFailed
}
return true
}
func (l *Lifeboat) Rollback() bool {
if l.LastKnownGood.ID == "" {
return false
}
l.Current = l.LastKnownGood
l.Current.State = ReleaseRolledBack
return true
}
+49
View File
@@ -0,0 +1,49 @@
package supervisor_test
import (
"git.cin.su/m/Assistant/runtime/supervisor"
"path/filepath"
"testing"
)
func TestLifeboatRollsBackCandidateToLastKnownGood(t *testing.T) {
l := supervisor.Lifeboat{}
l.Start(supervisor.Release{ID: "good", Version: "1"})
l.Record(supervisor.Observation{ReleaseID: "good", Ready: true})
l.Start(supervisor.Release{ID: "candidate", Version: "2"})
l.Record(supervisor.Observation{ReleaseID: "candidate", Ready: false})
if !l.Rollback() || l.Current.ID != "good" || l.Current.State != supervisor.ReleaseRolledBack {
t.Fatalf("%#v", l)
}
}
func TestPersistentLifeboatRestoresLastKnownGoodAfterCandidateFailure(t *testing.T) {
store, err := supervisor.NewDurableStore(filepath.Join(t.TempDir(), "control", "lifeboat.json"))
if err != nil {
t.Fatal(err)
}
first := supervisor.NewPersistentLifeboat(store)
if ok, err := first.Start(supervisor.Release{ID: "good", Version: "1"}); err != nil || !ok {
t.Fatalf("start good: %v %v", ok, err)
}
if ok, err := first.Record(supervisor.Observation{ReleaseID: "good", Ready: true, ObservedAtUnixMillis: 1}); err != nil || !ok {
t.Fatalf("record good: %v %v", ok, err)
}
if ok, err := first.Start(supervisor.Release{ID: "candidate", Version: "2"}); err != nil || !ok {
t.Fatalf("start candidate: %v %v", ok, err)
}
if ok, err := first.Record(supervisor.Observation{ReleaseID: "candidate", Ready: false, Reason: "candidate crashed", ObservedAtUnixMillis: 2}); err != nil || !ok {
t.Fatalf("record failure: %v %v", ok, err)
}
second := supervisor.NewPersistentLifeboat(store)
if ok, err := second.Rollback(); err != nil || !ok {
t.Fatalf("rollback after restart: %v %v", ok, err)
}
state, err := second.Snapshot()
if err != nil {
t.Fatal(err)
}
if state.Current.ID != "good" || state.Current.State != supervisor.ReleaseRolledBack || state.LastKnownGood.ID != "good" {
t.Fatalf("state=%+v", state)
}
}
+18
View File
@@ -0,0 +1,18 @@
package execution_outcome_test
import (
"git.cin.su/m/Assistant/contracts/commit"
"git.cin.su/m/Assistant/contracts/epistemics"
"testing"
)
func TestReportedExecutionSuccessIsNotWorldVerification(t *testing.T) {
r := commit.ExecutionReceipt{ID: "r", ActionAttemptRef: "a", ExecutorImplementationRef: "impl", RequestDigest: "d", ExecutorResult: commit.ExecutorReportedSuccess, ReconciliationKey: "k", DispatchAtUnixMillis: 1}
if !r.Valid() {
t.Fatal("receipt invalid")
}
o := epistemics.WorldOutcomeAssessment{ID: "o", PrincipalID: "p", ActionAttemptRef: "a", State: epistemics.OutcomeUnverified, ConfidenceMillis: 0, AssessedAt: 1}
if !o.Valid() {
t.Fatal("unverified assessment invalid")
}
}