latticerb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +176 -0
- data/README.md +121 -0
- data/exe/lattice +7 -0
- data/lib/lattice/agent.rb +153 -0
- data/lib/lattice/cli.rb +469 -0
- data/lib/lattice/constraints.rb +357 -0
- data/lib/lattice/formatters.rb +126 -0
- data/lib/lattice/ipog.rb +222 -0
- data/lib/lattice/mersenne_twister.rb +102 -0
- data/lib/lattice/model.rb +83 -0
- data/lib/lattice/parser.rb +387 -0
- data/lib/lattice/resources/claude/lattice-workflow/SKILL.md +142 -0
- data/lib/lattice/resources/claude/lattice-workflow/references/modeling-rules.md +52 -0
- data/lib/lattice/resources/claude/lattice-workflow/references/worked-examples.md +59 -0
- data/lib/lattice/resources/codex/lattice-workflow/SKILL.md +142 -0
- data/lib/lattice/resources/codex/lattice-workflow/agents/openai.yaml +7 -0
- data/lib/lattice/resources/codex/lattice-workflow/references/modeling-rules.md +52 -0
- data/lib/lattice/resources/codex/lattice-workflow/references/worked-examples.md +59 -0
- data/lib/lattice/resources/generic/lattice-workflow/SKILL.md +150 -0
- data/lib/lattice/resources/generic/lattice-workflow/references/modeling-rules.md +52 -0
- data/lib/lattice/resources/generic/lattice-workflow/references/worked-examples.md +59 -0
- data/lib/lattice/version.rb +5 -0
- data/lib/lattice.rb +87 -0
- data/lib/latticerb.rb +4 -0
- metadata +86 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Modeling Rules
|
|
2
|
+
|
|
3
|
+
Use this file when you are extracting a schema from code or prose and need tighter guardrails than the main skill body provides.
|
|
4
|
+
|
|
5
|
+
## Parameter Selection
|
|
6
|
+
|
|
7
|
+
- Scope one schema to one coherent behavior or rendering surface.
|
|
8
|
+
Good scopes: one feature, one service behavior, one workflow, one endpoint family, one state-machine slice, one component's variant space, one template family.
|
|
9
|
+
Bad default scope: the whole app.
|
|
10
|
+
- Model the decisions that change behavior, not every field in a payload.
|
|
11
|
+
- Prefer parameters that are visible in tests, UI branches, rendering branches, validation logic, template variants, component props, or feature flags.
|
|
12
|
+
- Split large raw domains into behavioral partitions.
|
|
13
|
+
Good: `pay_range = present|absent`
|
|
14
|
+
Bad: every exact salary string
|
|
15
|
+
- Avoid separate parameters for values that are already implied by another parameter unless the implication is partial and needs a constraint.
|
|
16
|
+
|
|
17
|
+
## Value Selection
|
|
18
|
+
|
|
19
|
+
- Values should be mutually exclusive and collectively useful for testing.
|
|
20
|
+
- Keep domains small and meaningful. Most parameters should land in the 2-5 value range.
|
|
21
|
+
- Normalize booleans as `true` and `false`.
|
|
22
|
+
- For optional subordinate parameters, let `conditional` introduce `N/A`. Do not hand-add `N/A` unless the schema genuinely needs it as a first-class value.
|
|
23
|
+
|
|
24
|
+
## Constraint Choice
|
|
25
|
+
|
|
26
|
+
- `invalid_pair`: two assignments cannot coexist
|
|
27
|
+
- `bidirectional`: one-to-one pairing; if A then B and if B then A
|
|
28
|
+
- `forward_dep`: A requires B, but B may appear elsewhere
|
|
29
|
+
- `conditional`: a child parameter only applies for some parent values
|
|
30
|
+
- `forced`: this assignment set must appear in at least one generated row
|
|
31
|
+
- `higher_order`: the invalid rule only appears when two or more antecedents are true
|
|
32
|
+
|
|
33
|
+
Choose the smallest expressive type. If a rule can be represented as `invalid_pair`, do not use `higher_order`.
|
|
34
|
+
|
|
35
|
+
Do not strip true constraints to get a smaller or easier unconstrained run. Do not generate nonsensical rows and mark them invalid downstream. Lattice's coverage accounting should run over valid interactions, so impossible combinations belong in the schema as `invalid_pair`, `forward_dep`, `bidirectional`, `conditional`, or `higher_order` constraints.
|
|
36
|
+
|
|
37
|
+
## Extraction Process
|
|
38
|
+
|
|
39
|
+
1. Choose the behavior or rendering surface you are modeling.
|
|
40
|
+
2. Start from branches, validations, and business rules inside that scope.
|
|
41
|
+
3. Convert prose like "only when", "must", "cannot", and "except" into candidate constraints.
|
|
42
|
+
4. Remove cosmetic parameters that do not affect behavior.
|
|
43
|
+
5. Check whether a missing value is really a separate partition or just noise.
|
|
44
|
+
6. Validate the schema.
|
|
45
|
+
7. Only after validation, generate scenarios.
|
|
46
|
+
|
|
47
|
+
## Interpretation
|
|
48
|
+
|
|
49
|
+
- Plan mode: each row becomes a review scenario or a missing decision in the plan.
|
|
50
|
+
- Test mode: each row becomes a candidate setup matrix. Source the expected behavior from intent — user request, spec, PRD, or ticket — not from the code under test. If you cannot determine intent for a row, stop and surface the ambiguity to the user. Do not encode the current behavior and label it `bug_signal:` to hedge: characterization tests pass for the wrong reasons and hide the asymmetries Lattice is designed to expose. Example: if a mailbox accepts a spoofed `From:` header today, the assertion is still "rejects spoofed sender" — let the test fail and fix the code, do not invert the assertion to match the bug.
|
|
51
|
+
- Variant mode: each row becomes a rendered variant, fixture, screenshot, visual diff input, contact-sheet item, or review checklist item.
|
|
52
|
+
- Generated rows are not test names by themselves. The agent still needs to map them to application-specific assertions.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Worked Examples
|
|
2
|
+
|
|
3
|
+
These examples live in the repo-level `examples/` directory.
|
|
4
|
+
|
|
5
|
+
## `examples/plan-mode-saved-search`
|
|
6
|
+
|
|
7
|
+
Use when the agent starts from a feature discussion or PRD and needs a review checklist.
|
|
8
|
+
|
|
9
|
+
- Input: `feature.md`
|
|
10
|
+
- Schema transport: `model.yaml`
|
|
11
|
+
- Output: `scenarios.json`
|
|
12
|
+
|
|
13
|
+
## `examples/test-mode-checkout`
|
|
14
|
+
|
|
15
|
+
Use when the agent starts from code and an existing test surface and needs missing cases.
|
|
16
|
+
|
|
17
|
+
- Input: `code-notes.md`
|
|
18
|
+
- Schema transport: `model.json`
|
|
19
|
+
- Output: `scenarios.json`
|
|
20
|
+
|
|
21
|
+
## `examples/three-way-notifications`
|
|
22
|
+
|
|
23
|
+
Use when pairwise is not enough and the user explicitly wants 3-way coverage.
|
|
24
|
+
|
|
25
|
+
- Input: `brief.md`
|
|
26
|
+
- Schema transport: `model.yaml`
|
|
27
|
+
- Output: `scenarios.json`
|
|
28
|
+
|
|
29
|
+
## `examples/component-variant-matrix`
|
|
30
|
+
|
|
31
|
+
Use when the agent starts from a visual component, rendering surface, template, or design-system story and needs compact review variants instead of every possible combination.
|
|
32
|
+
|
|
33
|
+
- Input: `brief.md`
|
|
34
|
+
- Schema transport: `model.yaml`
|
|
35
|
+
- Output: `scenarios.json`
|
|
36
|
+
|
|
37
|
+
## `examples/lattice-self-test`
|
|
38
|
+
|
|
39
|
+
Use when you want a meta example of the harness extracting a schema for Lattice's own CLI surface and then using generated rows to drive CLI smoke tests.
|
|
40
|
+
|
|
41
|
+
- Input: `brief.md`
|
|
42
|
+
- Schema transport: `model.yaml`
|
|
43
|
+
- Output: `scenarios.json`
|
|
44
|
+
|
|
45
|
+
## `examples/agent-bootstrap-matrix`
|
|
46
|
+
|
|
47
|
+
Use when you want a meta example of Lattice testing its own agent skill bootstrap behavior across harness detection, force/skip directives, target modes, and output formats.
|
|
48
|
+
|
|
49
|
+
- Input: `brief.md`
|
|
50
|
+
- Schema transport: `model.yaml`
|
|
51
|
+
- Output: `scenarios.json`
|
|
52
|
+
|
|
53
|
+
## `examples/schema-guidance-matrix`
|
|
54
|
+
|
|
55
|
+
Use when you want a meta example of Lattice testing its own schema-discoverability guidance across help text, agent instructions, installed skill files, and validation errors.
|
|
56
|
+
|
|
57
|
+
- Input: `brief.md`
|
|
58
|
+
- Schema transport: `model.yaml`
|
|
59
|
+
- Output: `scenarios.json`
|
data/lib/lattice.rb
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lattice/version"
|
|
4
|
+
require_relative "lattice/model"
|
|
5
|
+
require_relative "lattice/parser"
|
|
6
|
+
require_relative "lattice/constraints"
|
|
7
|
+
require_relative "lattice/ipog"
|
|
8
|
+
require_relative "lattice/formatters"
|
|
9
|
+
|
|
10
|
+
module Lattice
|
|
11
|
+
# A generation run: the parsed model plus its covering array, with
|
|
12
|
+
# ready-to-use named scenarios for tests, fixtures, and factories.
|
|
13
|
+
class Run
|
|
14
|
+
attr_reader :model, :result, :seed
|
|
15
|
+
|
|
16
|
+
def initialize(model:, result:, seed:)
|
|
17
|
+
@model = model
|
|
18
|
+
@result = result
|
|
19
|
+
@seed = seed
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Scenarios as an array of `{ "parameter" => "value" }` hashes.
|
|
23
|
+
def scenarios
|
|
24
|
+
@scenarios ||= Formatters.named_rows(model, result).each(&:freeze).freeze
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def each_scenario(&) = scenarios.each(&)
|
|
28
|
+
|
|
29
|
+
def coverage_curve = result.coverage_curve
|
|
30
|
+
|
|
31
|
+
def to_table = Formatters.render_output(model, result, output_format: "table", seed:)
|
|
32
|
+
def to_json_output = Formatters.render_output(model, result, output_format: "json", seed:)
|
|
33
|
+
def to_csv = Formatters.render_output(model, result, output_format: "csv", seed:)
|
|
34
|
+
def to_summary = Formatters.render_output(model, result, output_format: "summary", seed:)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class << self
|
|
38
|
+
# Parse a schema from a Hash (already-decoded JSON/YAML), a JSON or YAML
|
|
39
|
+
# String, or a file path via `file:`.
|
|
40
|
+
def parse_model(source = nil, file: nil, strength: nil)
|
|
41
|
+
if file
|
|
42
|
+
Parser.load_model(file, strength_override: strength)
|
|
43
|
+
elsif source.is_a?(Hash)
|
|
44
|
+
Parser.parse_model_data(source, strength_override: strength)
|
|
45
|
+
elsif source.is_a?(String)
|
|
46
|
+
data = Parser.deserialize_model(source, "string", nil)
|
|
47
|
+
Parser.parse_model_data(data, strength_override: strength)
|
|
48
|
+
elsif source.is_a?(Model)
|
|
49
|
+
strength ? source.with(strength:) : source
|
|
50
|
+
else
|
|
51
|
+
raise ArgumentError, "Pass a schema Hash, a JSON/YAML String, a Lattice::Model, or file: <path>."
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Generate a covering array for a schema and return a Run.
|
|
56
|
+
#
|
|
57
|
+
# run = Lattice.generate(file: "spec/fixtures/checkout.yaml")
|
|
58
|
+
# run.scenarios.each { |row| ... }
|
|
59
|
+
def generate(source = nil, file: nil, strength: nil, seed: 42, pool_size: 50,
|
|
60
|
+
max_rows: nil, stop_after_coverage: nil, progress: nil)
|
|
61
|
+
model = parse_model(source, file:, strength:)
|
|
62
|
+
result = IPOG.generate_covering_array(
|
|
63
|
+
model,
|
|
64
|
+
strength: model.strength,
|
|
65
|
+
seed:,
|
|
66
|
+
pool_size:,
|
|
67
|
+
progress:,
|
|
68
|
+
max_rows:,
|
|
69
|
+
stop_after_coverage:
|
|
70
|
+
)
|
|
71
|
+
Run.new(model:, result:, seed:)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Convenience: generate and return just the named scenario hashes.
|
|
75
|
+
def scenarios(...) = generate(...).scenarios
|
|
76
|
+
|
|
77
|
+
# Parse and constraint-check a schema, raising Lattice::ValidationError or
|
|
78
|
+
# Lattice::ConstraintError when invalid. Returns the Model.
|
|
79
|
+
def validate!(source = nil, file: nil, strength: nil)
|
|
80
|
+
model = parse_model(source, file:, strength:)
|
|
81
|
+
engine = ConstraintEngine.new(model)
|
|
82
|
+
raise ValidationError, ["Model has no valid complete assignments."] unless engine.can_complete?({})
|
|
83
|
+
|
|
84
|
+
model
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
data/lib/latticerb.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: latticerb
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Tyler Klose
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: csv
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '3.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '3.0'
|
|
26
|
+
description: Lattice generates deterministic pairwise/t-way covering arrays from a
|
|
27
|
+
constrained schema of parameters and values. Use it as a library in test suites
|
|
28
|
+
(RSpec, Minitest, Rails fixtures) or via the bundled `lattice` CLI. Output is row-for-row
|
|
29
|
+
identical to the Python lattice-cli package for the same schema and seed.
|
|
30
|
+
email:
|
|
31
|
+
- tylerklose@gmail.com
|
|
32
|
+
executables:
|
|
33
|
+
- lattice
|
|
34
|
+
extensions: []
|
|
35
|
+
extra_rdoc_files: []
|
|
36
|
+
files:
|
|
37
|
+
- LICENSE
|
|
38
|
+
- README.md
|
|
39
|
+
- exe/lattice
|
|
40
|
+
- lib/lattice.rb
|
|
41
|
+
- lib/lattice/agent.rb
|
|
42
|
+
- lib/lattice/cli.rb
|
|
43
|
+
- lib/lattice/constraints.rb
|
|
44
|
+
- lib/lattice/formatters.rb
|
|
45
|
+
- lib/lattice/ipog.rb
|
|
46
|
+
- lib/lattice/mersenne_twister.rb
|
|
47
|
+
- lib/lattice/model.rb
|
|
48
|
+
- lib/lattice/parser.rb
|
|
49
|
+
- lib/lattice/resources/claude/lattice-workflow/SKILL.md
|
|
50
|
+
- lib/lattice/resources/claude/lattice-workflow/references/modeling-rules.md
|
|
51
|
+
- lib/lattice/resources/claude/lattice-workflow/references/worked-examples.md
|
|
52
|
+
- lib/lattice/resources/codex/lattice-workflow/SKILL.md
|
|
53
|
+
- lib/lattice/resources/codex/lattice-workflow/agents/openai.yaml
|
|
54
|
+
- lib/lattice/resources/codex/lattice-workflow/references/modeling-rules.md
|
|
55
|
+
- lib/lattice/resources/codex/lattice-workflow/references/worked-examples.md
|
|
56
|
+
- lib/lattice/resources/generic/lattice-workflow/SKILL.md
|
|
57
|
+
- lib/lattice/resources/generic/lattice-workflow/references/modeling-rules.md
|
|
58
|
+
- lib/lattice/resources/generic/lattice-workflow/references/worked-examples.md
|
|
59
|
+
- lib/lattice/version.rb
|
|
60
|
+
- lib/latticerb.rb
|
|
61
|
+
homepage: https://github.com/tylerklose/lattice-ruby
|
|
62
|
+
licenses:
|
|
63
|
+
- Apache-2.0
|
|
64
|
+
metadata:
|
|
65
|
+
homepage_uri: https://github.com/tylerklose/lattice-ruby
|
|
66
|
+
source_code_uri: https://github.com/tylerklose/lattice-ruby
|
|
67
|
+
rubygems_mfa_required: 'true'
|
|
68
|
+
rdoc_options: []
|
|
69
|
+
require_paths:
|
|
70
|
+
- lib
|
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 3.2.0
|
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - ">="
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '0'
|
|
81
|
+
requirements: []
|
|
82
|
+
rubygems_version: 3.6.9
|
|
83
|
+
specification_version: 4
|
|
84
|
+
summary: Deterministic combinatorial coverage for agent workflows and constrained
|
|
85
|
+
variant surfaces.
|
|
86
|
+
test_files: []
|