Compare commits

...
Author SHA1 Message Date
m 29815c49b8 GEN2-002: add shared semantic primitives
CI / test (push) Successful in 52s
2026-08-29 02:08:20 +03:00
m c14ad7fd0b GEN2-001: accept owner registry and dependency rules
CI / test (push) Successful in 49s
2026-08-29 02:05:35 +03:00
16 changed files with 370 additions and 7 deletions
+52
View File
@@ -179,6 +179,30 @@
"database_schema": "interaction",
"boundary_class": "remote_capable",
"may_depend_on": ["contracts.identity", "contracts.situation", "contracts.epistemics", "contracts.cognitive", "platform.ids", "platform.events"]
},
"world": {
"id": "mod.world",
"owns": ["WorldObject", "WorldObjectKindDefinition", "WorldAlias", "FacetDefinition", "RelationDefinition", "IdentityResolutionCandidate", "IdentityResolutionDecision", "WorldLineage"],
"database_schema": "world",
"boundary_class": "remote_capable",
"may_depend_on": ["contracts.identity", "platform.ids", "platform.events"],
"forbidden": ["adapters.models", "adapters.temporal", "claims", "beliefs", "observations"]
},
"configuration": {
"id": "mod.configuration",
"owns": ["SettingDefinition", "SettingAssignment", "ConfigurationRevision", "ConfigurationChangeProvenance"],
"database_schema": "configuration",
"boundary_class": "remote_capable",
"may_depend_on": ["contracts.identity", "contracts.authority", "platform.ids", "platform.events", "platform.secrets"],
"forbidden": ["secret_values", "arbitrary_key_value_without_definition"]
},
"self": {
"id": "mod.self",
"owns": ["CompetenceAssessment", "WeaknessPattern", "DependencyAssessment", "LearningLedgerEntry", "ImprovementNeed", "SelfVersionView", "SelfEvaluationInterpretation"],
"database_schema": "self",
"boundary_class": "remote_capable",
"may_depend_on": ["contracts.capability", "contracts.epistemics", "contracts.artifact", "platform.ids", "platform.events"],
"forbidden": ["adapters.models", "tasks", "authority_grants", "code_release_switching"]
}
},
"platform": {
@@ -244,6 +268,26 @@
"cross_owner_write": "forbidden",
"cross_owner_application_join": "forbidden"
},
"runtime_topology_v2": {
"core_runtime": {
"modules": ["identity", "situation", "work", "epistemics", "capability", "artifact", "interaction", "world", "configuration", "self"]
},
"continuity_runtime": {"modules": ["continuity"]},
"commit_runtime": {"modules": ["authority", "commit"]},
"cognitive_workers": {"modules": [], "role": "replaceable reasoning/context workers; no canonical ownership"},
"supervisor_runtime": {"modules": [], "role": "release health, switch, rollback and recovery; not a semantic owner"}
},
"storage_topology_v2": {
"postgres_cluster": "assistant_primary",
"schemas": {
"identity": "identity_role", "authority": "authority_role", "situation": "situation_role", "work": "work_role",
"epistemics": "epistemics_role", "continuity": "continuity_role", "capability": "capability_role", "commit": "commit_role",
"artifact": "artifact_role", "interaction": "interaction_role", "world": "world_role", "configuration": "configuration_role", "self": "self_role"
},
"cross_owner_fk": "forbidden_by_default",
"cross_owner_write": "forbidden",
"cross_owner_application_join": "forbidden"
},
"invariants": [
{
"id": "INV-AUTH-001",
@@ -309,6 +353,14 @@
".gitea/workflows/ci.yml",
"cmd/devctl/**",
"dev/ACTIVE_TASK.json",
"docs/DOMOVOY_CONSTITUTION.md",
"docs/DOMOVOY_GEN2_GAP_MAP.md",
"architecture/GEN2_TARGET_ARCHITECTURE.md",
"architecture/GEN2_CANONICAL_DATA_MODEL.md",
"development/GEN2_MIGRATION_MAP.md",
"development/GEN2_MASTER_PLAN.md",
"development/GEN2_EXECUTION_CONTRACT.md",
"development/GEN2_TASK_INDEX.md",
"security/**"
],
"default_feature_task_authority": {
+66
View File
@@ -75,6 +75,30 @@ modules:
boundary_class: remote_capable
may_depend_on: [contracts.identity, contracts.situation, contracts.epistemics, contracts.cognitive, platform.ids, platform.events]
world:
id: mod.world
owns: [WorldObject, WorldObjectKindDefinition, WorldAlias, FacetDefinition, RelationDefinition, IdentityResolutionCandidate, IdentityResolutionDecision, WorldLineage]
database_schema: world
boundary_class: remote_capable
may_depend_on: [contracts.identity, platform.ids, platform.events]
forbidden: [adapters.models, adapters.temporal, claims, beliefs, observations]
configuration:
id: mod.configuration
owns: [SettingDefinition, SettingAssignment, ConfigurationRevision, ConfigurationChangeProvenance]
database_schema: configuration
boundary_class: remote_capable
may_depend_on: [contracts.identity, contracts.authority, platform.ids, platform.events, platform.secrets]
forbidden: [secret_values, arbitrary_key_value_without_definition]
self:
id: mod.self
owns: [CompetenceAssessment, WeaknessPattern, DependencyAssessment, LearningLedgerEntry, ImprovementNeed, SelfVersionView, SelfEvaluationInterpretation]
database_schema: self
boundary_class: remote_capable
may_depend_on: [contracts.capability, contracts.epistemics, contracts.artifact, platform.ids, platform.events]
forbidden: [adapters.models, tasks, authority_grants, code_release_switching]
platform:
allowed_packages:
- platform.ids
@@ -98,6 +122,20 @@ runtime_topology_v1:
modules: []
role: "replaceable cognition/context compilation workers; no canonical ownership"
runtime_topology_v2:
core_runtime:
modules: [identity, situation, work, epistemics, capability, artifact, interaction, world, configuration, self]
continuity_runtime:
modules: [continuity]
commit_runtime:
modules: [authority, commit]
cognitive_workers:
modules: []
role: "replaceable reasoning/context workers; no canonical ownership"
supervisor_runtime:
modules: []
role: "release health, switch, rollback and recovery; not a semantic owner"
storage_topology_v1:
postgres_cluster: assistant_primary
schemas:
@@ -115,6 +153,26 @@ storage_topology_v1:
cross_owner_write: forbidden
cross_owner_application_join: forbidden
storage_topology_v2:
postgres_cluster: assistant_primary
schemas:
identity: identity_role
authority: authority_role
situation: situation_role
work: work_role
epistemics: epistemics_role
continuity: continuity_role
capability: capability_role
commit: commit_role
artifact: artifact_role
interaction: interaction_role
world: world_role
configuration: configuration_role
self: self_role
cross_owner_fk: forbidden_by_default
cross_owner_write: forbidden
cross_owner_application_join: forbidden
invariants:
- id: INV-AUTH-001
property: "No external mutation without current valid authority and target/revision checks"
@@ -149,6 +207,14 @@ protected_paths:
- .gitea/workflows/ci.yml
- cmd/devctl/**
- dev/ACTIVE_TASK.json
- docs/DOMOVOY_CONSTITUTION.md
- docs/DOMOVOY_GEN2_GAP_MAP.md
- architecture/GEN2_TARGET_ARCHITECTURE.md
- architecture/GEN2_CANONICAL_DATA_MODEL.md
- development/GEN2_MIGRATION_MAP.md
- development/GEN2_MASTER_PLAN.md
- development/GEN2_EXECUTION_CONTRACT.md
- development/GEN2_TASK_INDEX.md
- security/**
default_feature_task_authority:
+7
View File
@@ -0,0 +1,7 @@
# Configuration contract boundary
Configuration owns typed and versioned `SettingDefinition` and
`SettingAssignment` records plus scoped resolution and change provenance.
Effective configuration is a derived result. Secret values never enter a
setting assignment; only a `SecretRef`/`CredentialRef` crosses the secrets
boundary into an authorized adapter or runtime.
+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
+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
+9
View File
@@ -0,0 +1,9 @@
# SELF contract boundary
SELF owns evidence-backed competence, weakness, dependency, learning, and
self-evaluation records. Raw evidence remains Epistemics-owned; capability
health remains Capability-owned; tasks and development remain Work-owned;
release switching remains Supervisor/runtime-owned.
SELF is observational/evaluative and is not a mandatory request-path
orchestrator or an authority source.
+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
+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
+9
View File
@@ -0,0 +1,9 @@
# World contract boundary
World owns typed, versioned referents and vocabulary: `WorldObject`, kind and
facet/relation definitions, aliases, identity-resolution decisions, and
merge/split lineage. It does not own observations, claims, beliefs, or the
truth of values about a referent; those remain Epistemics-owned evidence.
Cross-owner references are typed semantic references. They do not create
cross-owner foreign keys, joins, writes, or a generic `Entity(any)` API.
+97
View File
@@ -0,0 +1,97 @@
package world
import (
"fmt"
"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
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
}
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")
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
{
"task_file": "dev/tasks/ARCH-GEN2-000-adopt-gen2-constitution-architecture-documents-and-governance-mode.json",
"task_id": "ARCH-GEN2-000",
"task_file": "dev/tasks/GEN2-002-introduce-shared-gen2-data-primitives-without-shared-domain-semantics.json",
"task_id": "GEN2-002",
"task_revision": 1
}
+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")
}
}