Add a system-model gauge command with per-pattern knees and report-only bands #1547

Closed
opened 2026-11-04 21:38:28 +00:00 by jared · 2 comments
Owner

Problem

No system-model command prints the distance sweep, so the present threshold cannot be studied on a new codebase. Jared wants a sliding scale that adapts to each codebase. The only sweep code is a one-off script, docs/system-design-format/proof/distance-sweep/gauge_dump.rb. It hard-codes one machine path and two plugins, and it reads the private OpportunityScan#matches with send.

Observed

A knee over all patterns is 0.333 in os-backlog and 0.375 in os-sdlc, where nearly all matches are already in. Knees per pattern are clear for REPO, LAY, and HEX. GATE has no knee in os-backlog and a knee of 0.375 in os-sdlc, which is too loose to mean "implemented".

Reproduce

n/a: this is a new command.

Approach

Add system-model gauge <project-root> [--json]. It works on any project root that the other system-model commands accept. It prints, per pattern: filled-match counts at each sweep threshold, the knee, the knee gain, and the matches in each band.

The purpose of the bands is to find code that should fit a pattern and does not. Bands: present is distance at or below 0.05, as Match#present? defines it. Candidate is above 0.05, up to the knee. Far is above the knee. A pattern with a knee gain below the minimum gain, or with too few filled matches, has no knee, and all of its matches above 0.05 are candidates. The minimum gain (default 0.2) is data in Catalog. The gauge covers strict and loose patterns and labels each loose row, so partial matches of loose patterns reach a report. There is no cap: a band only sorts matches, and no band hides a match.

The gauge also lists every match with exactly one empty role as missing-role, with the role name, the component, and the size. These matches are outside the sweep, because they have no filled assignment. They are the case where a component needs a pattern and lacks one part.

The knee is the sweep distance with the largest value of normalized count minus normalized distance. Bands are report-only. They do not change Match#present?, Catalog.thresholds, or the ranking.

Required work:

  1. Expose matches through a public OpportunityScan method — check: absent send(:matches) in plugins/os-sdlc/**/*.rb
  2. Add the gauge command to the CLI — check: present gauge in plugins/os-sdlc/lib/os_sdlc/system_model/run.rb
  3. Delete the one-off script docs/system-design-format/proof/distance-sweep/gauge_dump.rb and point the proof file at system-model gauge — check: present system-model gauge in docs/system-design-format/proof/2026-11-04-distance-sweep.md

Acceptance criteria

  1. Given a project root, when system-model gauge runs, then it prints for each pattern the counts per threshold, the knee, the gain, the band of each filled match, sorted by distance, and each missing-role match.
  2. Given a pattern with a knee of 0.375, when the bands are computed, then its matches up to 0.375 are candidates, and none are dropped.
  3. Given a pattern with a gain below the minimum or too few filled matches, when the bands are computed, then all of its matches above 0.05 are candidates.
  4. Given a component of size 0, when the gauge runs, then it skips the component and does not fail.
  5. Given any gauge output, when opportunities runs, then its ranking and present list do not change.

Owner sketch

class OsSdlc::SystemModel::DistanceGauge
  def initialize(matches:, minimum_gain:)
  def rows
end

Non-goals

Changing the 0.05 threshold. #1546 decides that from expert labels.

Origin

  • Trigger: Jared's 2026-11-04 question on a sliding threshold, after the sweep in docs/system-design-format/proof/2026-11-04-distance-sweep.md
  • Improvised this session: gauge_dump.rb, a one-off script that reads private matches with send
  • Chain: sweep needs a script ← no command prints the sweep ← opportunities shows only present and ranked findings. IMPROVISATION: gauge_dump.rb
  • Root candidate: none found; searched gauge, knee, sweep, distance, band, system-model, OpportunityScan, opportunities, gauge_dump
  • Where: plugins/os-sdlc/lib/os_sdlc/system_model/opportunity_scan.rb
  • Session: 16528b06-720e-4ee8-b195-838770c1efe8
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/16528b06-720e-4ee8-b195-838770c1efe8.jsonl

VERDICT: CREATE

## Problem No `system-model` command prints the distance sweep, so the present threshold cannot be studied on a new codebase. Jared wants a sliding scale that adapts to each codebase. The only sweep code is a one-off script, `docs/system-design-format/proof/distance-sweep/gauge_dump.rb`. It hard-codes one machine path and two plugins, and it reads the private `OpportunityScan#matches` with `send`. ## Observed A knee over all patterns is 0.333 in os-backlog and 0.375 in os-sdlc, where nearly all matches are already in. Knees per pattern are clear for REPO, LAY, and HEX. GATE has no knee in os-backlog and a knee of 0.375 in os-sdlc, which is too loose to mean "implemented". ## Reproduce n/a: this is a new command. ## Approach Add `system-model gauge <project-root> [--json]`. It works on any project root that the other `system-model` commands accept. It prints, per pattern: filled-match counts at each sweep threshold, the knee, the knee gain, and the matches in each band. The purpose of the bands is to find code that should fit a pattern and does not. Bands: present is distance at or below 0.05, as `Match#present?` defines it. Candidate is above 0.05, up to the knee. Far is above the knee. A pattern with a knee gain below the minimum gain, or with too few filled matches, has no knee, and all of its matches above 0.05 are candidates. The minimum gain (default 0.2) is data in `Catalog`. The gauge covers strict and loose patterns and labels each loose row, so partial matches of loose patterns reach a report. There is no cap: a band only sorts matches, and no band hides a match. The gauge also lists every match with exactly one empty role as missing-role, with the role name, the component, and the size. These matches are outside the sweep, because they have no filled assignment. They are the case where a component needs a pattern and lacks one part. The knee is the sweep distance with the largest value of normalized count minus normalized distance. Bands are report-only. They do not change `Match#present?`, `Catalog.thresholds`, or the ranking. Required work: 1. Expose matches through a public `OpportunityScan` method — check: absent `send(:matches)` in `plugins/os-sdlc/**/*.rb` 2. Add the `gauge` command to the CLI — check: present `gauge` in `plugins/os-sdlc/lib/os_sdlc/system_model/run.rb` 3. Delete the one-off script `docs/system-design-format/proof/distance-sweep/gauge_dump.rb` and point the proof file at `system-model gauge` — check: present `system-model gauge` in `docs/system-design-format/proof/2026-11-04-distance-sweep.md` ## Acceptance criteria 1. Given a project root, when `system-model gauge` runs, then it prints for each pattern the counts per threshold, the knee, the gain, the band of each filled match, sorted by distance, and each missing-role match. 2. Given a pattern with a knee of 0.375, when the bands are computed, then its matches up to 0.375 are candidates, and none are dropped. 3. Given a pattern with a gain below the minimum or too few filled matches, when the bands are computed, then all of its matches above 0.05 are candidates. 4. Given a component of size 0, when the gauge runs, then it skips the component and does not fail. 5. Given any gauge output, when `opportunities` runs, then its ranking and present list do not change. ## Owner sketch ```ruby class OsSdlc::SystemModel::DistanceGauge def initialize(matches:, minimum_gain:) def rows end ``` ## Non-goals Changing the 0.05 threshold. #1546 decides that from expert labels. ## Origin - Trigger: Jared's 2026-11-04 question on a sliding threshold, after the sweep in `docs/system-design-format/proof/2026-11-04-distance-sweep.md` - Improvised this session: `gauge_dump.rb`, a one-off script that reads private matches with `send` - Chain: sweep needs a script ← no command prints the sweep ← `opportunities` shows only present and ranked findings. IMPROVISATION: `gauge_dump.rb` - Root candidate: none found; searched gauge, knee, sweep, distance, band, system-model, OpportunityScan, opportunities, gauge_dump - Where: `plugins/os-sdlc/lib/os_sdlc/system_model/opportunity_scan.rb` - Session: 16528b06-720e-4ee8-b195-838770c1efe8 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/16528b06-720e-4ee8-b195-838770c1efe8.jsonl VERDICT: CREATE
Author
Owner

Work started on branch ticket-1547.

Work started on branch ticket-1547.
Author
Owner

Resolution

Done: Added system-model gauge: per-pattern sweep counts, knee with min-max normalization, gain, report-only bands, and every match with one or more empty roles. Deleted gauge_dump.rb.

Evidence: main; suite 3358 runs 0 failures; lint clean on 10 changed files; design audit findings all fixed; gauge run on os-backlog gives HEX 0.143, LAY 0.143, no false REPO knee.

Follow-ups: dropped: move the 0.05 literal to one owner, since Sweep and Match agree and #1546 may change it; dropped: print best-lift when no knee qualifies, since the gauge shows gain

## Resolution **Done:** Added system-model gauge: per-pattern sweep counts, knee with min-max normalization, gain, report-only bands, and every match with one or more empty roles. Deleted gauge_dump.rb. **Evidence:** main; suite 3358 runs 0 failures; lint clean on 10 changed files; design audit findings all fixed; gauge run on os-backlog gives HEX 0.143, LAY 0.143, no false REPO knee. **Follow-ups:** dropped: move the 0.05 literal to one owner, since Sweep and Match agree and #1546 may change it; dropped: print best-lift when no knee qualifies, since the gauge shows gain
jared closed this issue 2026-11-04 23:28:06 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#1547
No description provided.