Class: Reeve::Testing::Checks::ContractVersion

Inherits:
Base
  • Object
show all
Defined in:
lib/reeve/testing/checks/contract_version.rb

Overview

FR-015: the ledger the host actually migrated implements the entry shape this version of the gem writes.

The audit-entry contract is versioned in prose and in Audit::CONTRACT_VERSION; what this check adds is the third party to that agreement — the table. A host that upgraded the gem and skipped the migration has a ledger one shape behind, and every other check in this kit would go on passing while columns quietly went unwritten.

What each half of this check is worth, stated plainly because it is easy to read more into the version number than it carries:

  • The column list is the real test. It is compared against the columns the host's table actually has, and it is written out by hand rather than read back off the model — a check that derives its expectation from the thing it is checking checks nothing.
  • The version number is compared against what the ledger model reports, which is this gem's own Audit::CONTRACT_VERSION — so by default it compares the gem to itself and can only pass. It earns its keep when a host passes expected: to pin the version it built its exports against.

Those two are not as separate as they look, and that is by design. A contract bump is defined as a change to the shape or to what a value means; every such bump also moves the contract_version column, which means the column list catches a stale table even when the bump was purely semantic. Contract 2 is the worked example: the change was metadata's meaning, no existing column moved, and a host still on the contract 1 table fails here on a missing contract_version column rather than passing while writing rows nothing can interpret.

The constant below is written out rather than read from Audit for the same reason the column list is, and one more: the testing kit loads with no ledger and no ActiveRecord at all (spec/reeve/testing/isolation_spec.rb), so it cannot reference the audit module. Bumping the contract means editing both by hand, and spec/reeve/audit/contract_version_spec.rb fails if they drift.

Reeve::Checks::ContractVersion.new.call
Reeve::Checks::ContractVersion.new(expected: 2).call   # pinned by the host

Constant Summary collapse

TABLE =
"reeve_audit_entries"
COLUMNS =
%w[
  invocation_id occurred_at agent_id agent_name principal_type principal_id
  tool_name arguments outcome rule detail record_type record_ids record_count
  truncated derived guard duration_ms metadata contract_version
].freeze
EXPECTED_VERSION =
2

Instance Method Summary collapse

Methods inherited from Base

check_name, #check_name

Constructor Details

#initialize(tool: nil, expected: EXPECTED_VERSION, ledger: nil) ⇒ ContractVersion

Returns a new instance of ContractVersion.



53
54
55
56
# File 'lib/reeve/testing/checks/contract_version.rb', line 53

def initialize(tool: nil, expected: EXPECTED_VERSION, ledger: nil)
  super(tool: tool, ledger: ledger)
  @expected = expected
end

Instance Method Details

#callObject



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/reeve/testing/checks/contract_version.rb', line 58

def call
  return ledger_unavailable("the audit-entry contract version") unless ledger.available?

  recorded = ledger.contract_version
  return version_mismatch(recorded) unless recorded == @expected

  missing = COLUMNS - ledger.columns
  return missing_columns(missing) unless missing.empty?

  passed("the ledger implements audit-entry contract version #{@expected}",
         version: @expected)
end