Skip to content

feat: motif-basis fingerprint v2 — triad census, weighted TV drift, quotient k=1 (Part B)#144

Merged
zaebee merged 20 commits into
mainfrom
feat/motif-basis-part-b
Jun 10, 2026
Merged

feat: motif-basis fingerprint v2 — triad census, weighted TV drift, quotient k=1 (Part B)#144
zaebee merged 20 commits into
mainfrom
feat/motif-basis-part-b

Conversation

@zaebee

@zaebee zaebee commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Implements Part B of the pattern-alphabet / motif-basis spec (docs/specs/2026-06-09-pattern-alphabet-motif-basis-design.md §3.2–3.4, merged in #142). Plan: docs/specs/plans/2026-06-10-motif-basis-part-b.md.

What's new

13-triad census (query/triads.py)

  • Connected directed triad census via the Batagelj–Mrvar tricode table (64 entries) — no networkx dependency. Cross-validated against networkx on 30 random graphs (30/30 match); the cross-check caught a 120D↔120U label swap in the plan's hand-written tests before it shipped.
  • normalized_census (raw ratios, no null-model z-scores per spec §3.2) and weighted total-variation distance tv_distance with per-triad contribution decomposition.

Fingerprint v2 (query/fingerprint.py)

  • PatternFingerprint gains t_imports / t_calls census vectors, computed per-layer over domain-internal edges.
  • FingerprintExtractor.from_graph() preload path (used by quotient scoring) with defensive copies.

Drift scoring v2 (query/drift.py)

  • drift = Σ eff_k·tv_k / Σ eff_k over layers {imports, calls, gates}; CALLS discounted by clip(1 − unresolved_ratio); empty layers are excluded and renormalized — no data ≠ maximally drifted.
  • v2 activates only when the template declares ideal: and the profile declares layers: — legacy configs hit the untouched v1 path. drift_score is now uniformly unrounded on both paths.

Quotient k=1 (query/quotient.py)

  • Domains collapse to quotient.<name> MODULE nodes; cross-domain IMPORTS/CALLS aggregate with weight = count (the le=1.0 bound on Edge.weight was removed — verified no consumer reads the magnitude). Longest-prefix domain matching, fully deterministic edge ordering.
  • Scored by the same FingerprintExtractor + DriftScorer — closure under coarsening is the point. Bound observe-only (enforce: false) for the burn-in milestone: reported, never flips the exit code.

patterns.yaml v2.1 + CLI

  • Profiles gain layers: weights; all 5 templates gain ideal: census points; per-domain tolerances re-baselined against measured v2 drifts (annotated # measured); project_level: binding cgis-project → pipeline_stage, observe-only.
  • cgis drift table gains TV imp / TV calls columns; quotient line + JSON entries carry the enforce flag.

Validation (plan Task 7)

Every hand-computed v2 prediction matched measurement within 0.003:
extraction 0.262/tol 0.30 · resolution 0.350/0.40 · pipeline 0.196/0.25 · storage 0.166/0.20 · query 0.141/0.18 · components 0.167/0.20 · layout 0.455/0.50 · hygiene-only 0.00. Quotient measures 0.700 vs pipeline_stage (exact arithmetic: orchestrator reality, expected — rebind decision deferred to post-burn-in).

Out of scope (deferred by design)

Quotient rebind to orchestrator, TS quotient binding, quotient unresolved_ratio plumbing, removing v1 counting fields, Part C.

Test plan

  • 522 unit + self-parsing tests green
  • mypy strict clean (33 files), ruff clean, doc coverage 99.6%
  • networkx cross-validation of the tricode table (30/30 random graphs)
  • smoke: cgis ingest src && cgis drift — exit 0, quotient observe-only line rendered
  • final whole-branch integration review: APPROVE

🤖 Generated with Claude Code

zaebee and others added 18 commits June 10, 2026 09:58
9 TDD tasks: triad census (no new deps), census vectors on
PatternFingerprint, ideal/layers/triad_weights config, v2 TV scoring with
empty-layer exclusion, quotient builder, patterns.yaml v2.1 with
re-baselined tolerances, observe-only quotient self-test, CLI TV columns,
spec §3.3 example amendment. Baseline measured live 2026-06-10 (networkx
cross-check); all design deviations from spec documented with measurement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… §3.2)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…spec §3.3-3.4)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…erm (spec §3.3)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds build_quotient() that collapses each domain to one MODULE node and
aggregates cross-domain IMPORTS/CALLS edges by (src, dst, type) with
weight = count. Relaxes Edge.weight upper bound (le=1.0 → unbounded) to
allow aggregated counts > 1.0 in quotient edges.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ces, project_level (spec §3.3-3.4)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ot layering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the Motif-Basis Fingerprint v2 (Part B) design, replacing heuristic topological constraint scoring with a 13-triad census fingerprint and weighted total-variation distance to ideal points. It introduces a new triads module for census and TV distance calculations, adds census vectors to PatternFingerprint, implements a domain-quotient graph builder, and updates the DriftScorer with a v2 scoring path. The CLI is also updated to display TV columns and observe-only quotient drift. The reviewer feedback focuses on enhancing robustness by defensively clipping calculated ratio-based values (such as TV distance and drift scores) to the [0.0, 1.0] range, and validating that configuration blocks are dictionaries before parsing them to prevent runtime errors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/cgis/query/triads.py
Comment thread src/cgis/query/drift.py
Comment thread src/cgis/query/drift.py
Comment thread src/cgis/query/drift.py
Comment thread src/cgis/query/drift.py
Comment thread src/cgis/query/drift.py
…s, census complexity

- shared _validate_mapping helper; ideal layers / profile layers /
  triad_weights now fail loud (TypeError) on non-mapping YAML blocks
  (gemini; same precedent as Part A's _params_mapping)
- layers and triad_weights validated non-negative at load time —
  addresses the clip-to-[0,1] concern at the config layer instead of
  silently mangling computed TV/drift outputs
- triad_census split into _adjacency + _connected_triples (sonar
  cognitive complexity 21 -> below threshold)
- float equality in tests replaced with pytest.approx (sonar reliability)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@zaebee

zaebee commented Jun 10, 2026

Copy link
Copy Markdown
Owner Author

/gemini review

@zaebee

zaebee commented Jun 10, 2026

Copy link
Copy Markdown
Owner Author

/guardian review

@github-actions

Copy link
Copy Markdown
Contributor

LGTM — no defects found in this diff.

I have performed a high-precision, line-by-line review of the Pull Request diff. The implementation is of exceptional quality and fully complies with all engineering standards, type discipline, and the project ontology.

Verified Correctness & Components Audited:

  1. Batagelj–Mrvar Tricode & Triad Census (triads.py):

    • The 64-entry _TRICODES table and the 6-bit encoding scheme in _classify were verified against standard triadic census specifications.
    • _connected_triples correctly filters and yields unique sorted triples, avoiding double-counting or infinite loops, with an efficient complexity of $O(\sum \text{deg}(v)^2)$.
    • normalized_census safely handles empty graphs by returning ZERO_TRIADS instead of raising a ZeroDivisionError (NaN).
  2. Domain-Quotient Graph Construction (quotient.py):

    • Longest-prefix matching on nested domains is robustly handled by sorting domain prefixes in descending order of length (reverse=True).
    • Properly maps multi-layered cross-domain edges (IMPORTS, CALLS) while discarding self-loops and out-of-domain connections.
    • Removing the le=1.0 validator constraint on the Edge.weight Pydantic field is correctly coordinated with build_quotient, where aggregated edge weights represent count values $&gt;1.0$.
  3. V2 Drift Scoring Algebra (drift.py):

    • Division-by-zero checks are cleanly implemented via total > 0.0 check on the sum of the effective layer weights.
    • Gate calculations and the $1 - \text{unresolved_ratio}$ confidence discount are defensively bounded between [0, 1] via _clip_discount to prevent negative weights.
    • _validate_mapping raises exact, descriptive TypeError exceptions if hand-edited list elements are injected where YAML mappings are expected.

🤖 gemini-3.5-flash · 54,132 prompt + 451 completion = 54,583 tokens · graph 0/12 files (0%)

github-actions Bot added a commit that referenced this pull request Jun 10, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the Motif-Basis Fingerprint v2 (Part B) architecture, replacing heuristic topological constraint scoring with a 13-triad census fingerprint and weighted total-variation distance to ideal points. It introduces a new triads.py module for triad census and TV distance calculations, updates PatternFingerprint with census vectors, and implements a v2 scoring path in DriftScorer. Additionally, it adds a quotient.py module to construct domain-quotient graphs, updates patterns.yaml to v2.1, and enhances the CLI to display TV columns and observe-only quotient drift. Review feedback suggests defensively clipping the calculated drift score to the [0.0, 1.0] range in drift.py and refactoring the manual edge aggregation loop in quotient.py to use a declarative Counter comprehension.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/cgis/query/drift.py
Comment thread src/cgis/query/quotient.py Outdated
…ehension

Review round 2 (gemini): declarative comprehension matches the style of
the rest of build_quotient; behavior unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@zaebee zaebee merged commit 8a63efe into main Jun 10, 2026
3 checks passed
@zaebee zaebee deleted the feat/motif-basis-part-b branch June 10, 2026 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant