Class: Textus::Manifest::Policy

Inherits:
Object
  • Object
show all
Defined in:
lib/textus/manifest/policy.rb

Overview

Authority over zones and roles derived from a Manifest::Data snapshot. Encapsulates the lookups previously living on Manifest itself (zone_writers, permission_for). Write authority is derived from capabilities × zone-kind (ADR 0030): each zone-kind requires one verb (Schema::KIND_REQUIRES_VERB) and a role may write a zone iff its caps include that verb (verb_for_zone, roles_with_capability). Derived / proposal-queue status is authoritative via the declared-kind family (declared_kind, derived_entry?, queue_zone?, queue_zone).

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Policy

Returns a new instance of Policy.



12
13
14
# File 'lib/textus/manifest/policy.rb', line 12

def initialize(data)
  @data = data
end

Instance Method Details

#actor_for(verb) ⇒ Object

The role textus acts AS for a system-initiated operation requiring ‘verb` (no human passed –as). Capability-derived — a role name that exists in the manifest, or nil. Never a hardcoded literal (ADR 0044).



40
41
42
# File 'lib/textus/manifest/policy.rb', line 40

def actor_for(verb)
  roles_with_capability(verb).first
end

#declared_kind(zone_name) ⇒ Object

The kind declared on a zone in the manifest, or nil if undeclared.



60
61
62
# File 'lib/textus/manifest/policy.rb', line 60

def declared_kind(zone_name)
  @data.declared_zone_kinds[zone_name]
end

#derived_entry?(key) ⇒ Boolean

ADR 0091: derived-ness is a property of the ENTRY, not its zone (one machine zone holds both intake and derived entries). Resolve the entry and ask it directly. Returns false if entries are not yet built (validator phase during Data#initialize) — validators must not rely on cross-entry state during construction.

Returns:

  • (Boolean)


80
81
82
83
84
85
# File 'lib/textus/manifest/policy.rb', line 80

def derived_entry?(key)
  return false if @data.entries.nil?

  entry = @data.entries.find { |e| e.key == key } or return false
  entry.derived?
end

#machine_zoneObject

The single zone declaring kind: machine, or nil.



88
89
90
# File 'lib/textus/manifest/policy.rb', line 88

def machine_zone
  @data.declared_zone_kinds.key(:machine)
end

#permission_for(zone_name) ⇒ Object



52
53
54
55
56
57
# File 'lib/textus/manifest/policy.rb', line 52

def permission_for(zone_name)
  Textus::Domain::Permission.new(
    zone: zone_name,
    writers: zone_writers(zone_name),
  )
end

#propose_zone_for(role) ⇒ Object

The zone a proposer role writes proposals into: the single zone that declares kind: queue, when the role can write it. Returns nil if there is no queue zone or the role cannot write it.



100
101
102
103
104
105
106
107
# File 'lib/textus/manifest/policy.rb', line 100

def propose_zone_for(role)
  return nil if role.nil?

  q = queue_zone
  return nil unless q && zone_writers(q).include?(role)

  q
end

#proposer_roleObject

The conventional automated proposer: a role that can propose but is not the author-anchor (so it resolves to ‘agent`, not `human`, under the default mapping). Falls back to the first proposer, then nil.



32
33
34
35
# File 'lib/textus/manifest/policy.rb', line 32

def proposer_role
  proposers = roles_with_capability("propose")
  (proposers - roles_with_capability("author")).first || proposers.first
end

#queue_zoneObject

The single zone declaring ‘kind: queue`, or nil. Schema guarantees <=1.



71
72
73
# File 'lib/textus/manifest/policy.rb', line 71

def queue_zone
  @data.declared_zone_kinds.key(:queue)
end

#queue_zone?(zone_name) ⇒ Boolean

A zone is a proposal queue iff it declares kind: queue.

Returns:

  • (Boolean)


93
94
95
# File 'lib/textus/manifest/policy.rb', line 93

def queue_zone?(zone_name)
  declared_kind(zone_name) == :queue
end

#roles_with_capability(verb) ⇒ Object

Names of roles whose declared caps include ‘verb`.



25
26
27
# File 'lib/textus/manifest/policy.rb', line 25

def roles_with_capability(verb)
  @data.role_caps.select { |_name, caps| caps.include?(verb) }.keys
end

#verb_for_zone(zone_name) ⇒ Object

The capability a zone’s kind requires to be written, or nil if the zone declares no kind. declared_kind returns a Symbol; the table is keyed by String.



19
20
21
22
# File 'lib/textus/manifest/policy.rb', line 19

def verb_for_zone(zone_name)
  kind = declared_kind(zone_name)
  kind && Schema::KIND_REQUIRES_VERB[kind.to_s]
end

#zone_writers(zone_name) ⇒ Object

The roles authorized to write ‘zone_name`: those holding the verb its kind requires. Raises on an undeclared zone.

Raises:



46
47
48
49
50
# File 'lib/textus/manifest/policy.rb', line 46

def zone_writers(zone_name)
  raise UsageError.new("undeclared zone '#{zone_name}'") unless @data.declared_zone_kinds.key?(zone_name)

  roles_with_capability(verb_for_zone(zone_name))
end

#zones_of_kind(kind) ⇒ Object

Zone names declaring ‘kind` (a Symbol), in manifest order. Lets callers (boot) name a kind’s live zone instance(s) instead of hardcoding names.



66
67
68
# File 'lib/textus/manifest/policy.rb', line 66

def zones_of_kind(kind)
  @data.declared_zone_kinds.select { |_name, k| k == kind }.keys
end