Skip to content

docs(specs): drift gate semantics v2 — intra-domain cycles, gate_failed, tolerance precedence (#176 + #170)#216

Merged
zaebee merged 3 commits into
mainfrom
docs/spec-176-170-gate-semantics
Jun 12, 2026
Merged

docs(specs): drift gate semantics v2 — intra-domain cycles, gate_failed, tolerance precedence (#176 + #170)#216
zaebee merged 3 commits into
mainfrom
docs/spec-176-170-gate-semantics

Conversation

@zaebee

@zaebee zaebee commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

Combined design spec for #176 + #170 (roadmap #179 P1 — "make the gate correct across topologies"). One spec because both change what the gate means, and the cycle fix interacts with both #170 halves AND #174's round-trip guarantee.

Key content:

  • Corrected diagnosis for cycle_ratio: split import-cycles (real smell) from intra-module call-cycles (benign); flat repos give false criticals #176: CALLS edges never enter the cycle computation — the httpx wall is the blast radius of FILE-level import cycles propagated per-node, denominated per-domain (granularity artifact). The issue's proposed call_cycle_ratio would gate a thing the metric never measured; explicitly NOT built
  • Fix: intra-domain SCC (user-decided) — cycle_ratio from the domain's OWN import subgraph; single-file domains → 0 by construction; cross-domain cycles routed to the quotient layer (030C motifs) as a pinned principle
  • gate_failed status (user-decided) — hygiene-provenance violations force it regardless of TV score, undilutable; trips any_critical when enforced
  • Acknowledgeable hygiene baselines — the Add cgis init-ontology: auto-propose patterns.yaml from measured graph #174-interaction fix found during design: naive "breach always fails" would make init-ontology produce instantly-failing baselines on any cyclic repo. hygiene_baseline: per-domain = acknowledged debt (ratchet-down convention); init-ontology emits it for measured breaches → round-trip guarantee survives, NEW debt beyond baseline fails absolutely
  • Tolerance precedence (user-decided, ⚠️ breaking): per-domain drift_tolerance binds; max_drift demoted to default-for-undeclared; relative warning band (0.75×); the gate becomes uniformly status-based and enforce-respecting (also retires the cgis_drift: zero-match / no-signal domains report 'clean' instead of 'empty' (silent mis-targeted ontology passes green) #178-era "score term is enforce-blind" deferral)

Test Plan

🤖 Generated with Claude Code

…lerance precedence (#176, #170)

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

zaebee commented Jun 12, 2026

Copy link
Copy Markdown
Owner Author

/guardian review

@github-actions github-actions 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.

LGTM — no defects found in this diff.

Diff is a design specification document (markdown), not executable code. No logic, type safety, or ontology violations to flag. Verified no code changes or test gaps in the provided diff.


🤖 mistral-medium-latest · 6,347 prompt + 50 completion = 6,397 tokens

github-actions Bot added a commit that referenced this pull request Jun 12, 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 introduces a design specification for Drift Gate Semantics v2, addressing intra-domain cycles, a new gate_failed status, and per-domain tolerance precedence. The feedback suggests key improvements to the spec: making the effective bound resolution operator-aware to support both min and max constraints, validating that the hygiene_baseline configuration is a mapping before parsing, and ensuring the loader safely handles the optional drift_tolerance field when it is missing or null.

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 docs/specs/2026-06-12-gate-semantics-design.md Outdated
Comment thread docs/specs/2026-06-12-gate-semantics-design.md Outdated
Comment thread docs/specs/2026-06-12-gate-semantics-design.md Outdated
…tolerance loader (gemini review)

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

@zaebee zaebee left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Spec review — strong, 2 design points to nail before implementation

Read it end to end. The corrected #176 diagnosis (§1.1: CALLS edges never enter the cycle computation_compute_cycles is Tarjan over IMPORTS between FILE/MODULE nodes, and the wall is per-domain blast-radius of file-level import cycles) is right and well-argued, and explicitly not building call_cycle_ratio is the correct call. Intra-domain SCC (§2.1) with single-file→0-by-construction is clean. Operator-aware baseline resolution and the enforce-uniform any_critical (retiring the #178 score-term deferral) are good. Two things I'd resolve before/in the impl:

1. Hygiene/template key collision makes gate_failed provenance ambiguous (§2.2) — and it's LIVE

score() keeps {**hygiene, **template} and adds a "which keys came from hygiene" set. But unresolved_ratio is declared in BOTH — hygiene {max: 0.2} and the pure_utility template {max: 0.1}. After the merge the template wins (0.1), yet the key is still "hygiene-provenance" → a domain at unresolved_ratio 0.15 (violates the template's 0.1, satisfies the hygiene invariant 0.2) would be forced to gate_failed / undilutable — escalating a template breach as if it were a hygiene-invariant breach.

Suggest evaluating hygiene and template constraints separately (don't dict-merge), each judged against its own bound with its own provenance. That also removes the need for a side "provenance key set". The collision is real in today's patterns.yaml, so this isn't hypothetical.

2. The emitted hygiene_baseline must round UP, or init-ontology fails its own round-trip (§2.2)

The whole point of the baseline is the #174 round-trip: init-ontologydrift on the proposal must stay green. With effective bound max(global_max=0.0, baseline), the gate passes only if measured <= baseline. So the emitted baseline must be ≥ the measured value — exact, or _ceil2-style ceil, never floored to 2dp. If init-ontology emits 0.08 for a measured 0.0833, the proposal gate_faileds on its own graph. Pin the rounding direction the same way tolerances use _ceil2.

Smaller notes

  • Sequencing: the hygiene_baseline emission rides on ontology_init.py, i.e. this impl should land after #211 merges.
  • §2.1 tarjan reuse: make sure the SCC helper is a shared module-level util, not reached into via HealthScorer internals (fingerprint→health private coupling).
  • §2.2 stray baselines: a hygiene_baseline declared for a non-hygiene key should be validated/ignored — say so, or it silently no-ops.

None are blockers for the spec#1 and #2 are the two I'd want pinned in the doc before the plan, since both touch correctness (undilutability semantics, and the round-trip guarantee this section exists to protect). Nice work on the diagnosis especially.

…shared tarjan, strict baseline keys (colleague review)

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

zaebee commented Jun 12, 2026

Copy link
Copy Markdown
Owner Author

Re: the spec review — all five folded in (be41007):

  1. Key collision — accepted, and it reshapes §2.2 for the better. You're right that the merged-dict + provenance-set design escalates a template breach into a false gate_failed on the LIVE unresolved_ratio collision (hygiene 0.2 vs pure_utility 0.1). The spec now mandates SEPARATE evaluation of the two constraint sets, each against its own bounds — a both-declared key is checked twice, which is the honest semantics (invariant ≠ ideal), and the provenance side-set disappears entirely. Cleaner design than what it replaces.
  2. Baseline rounding — accepted as load-bearing: emission pins _ceil2 (round UP), with your floored-0.08-vs-measured-0.0833 failure mode quoted as the rationale.
  3. Sequencing — noted in the header; feat(query): cgis init-ontology — auto-proposed patterns.yaml (#174) #211 merged earlier today, so the dependency is already satisfied.
  4. Shared tarjan — §2.1 now requires the module-level util import, no HealthScorer reach-in.
  5. Stray baseline keys — rejected at load time with a descriptive error ("a silently no-op'ing acknowledgment would be worse than none").

The unresolved_ratio collision catch especially — that one would have shipped as a subtle wrong-escalation. Thanks.

🤖 Generated with Claude Code

@sonarqubecloud

Copy link
Copy Markdown

@zaebee zaebee merged commit ae120a1 into main Jun 12, 2026
3 checks passed
@zaebee zaebee deleted the docs/spec-176-170-gate-semantics branch June 12, 2026 20:17
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.

cycle_ratio: split import-cycles (real smell) from intra-module call-cycles (benign); flat repos give false criticals

1 participant