Skip to content

Canonical fix: persist fully_diluted_supply even when incoherent with total_supply#118

Merged
fafa33 merged 2 commits into
mainfrom
fix/supply-coherence-tolerance
Jul 26, 2026
Merged

Canonical fix: persist fully_diluted_supply even when incoherent with total_supply#118
fafa33 merged 2 commits into
mainfrom
fix/supply-coherence-tolerance

Conversation

@fafa33

@fafa33 fafa33 commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Summary

Independent review (Codex, on PR #110) flagged that Sky's persisted SupplyBasisSnapshot had no fully_diluted_supply component — an interim omission-based fix (PR #117) that satisfied SupplyBasisSnapshot's canonical total<=fully_diluted invariant but didn't actually satisfy ADR 0022 Scope condition 3 (all three supply quantities independently observable). This PR fixes the canonical architecture instead of the acquisition script: SupplyBasisSnapshot.__post_init__ no longer hard-rejects total_supply > fully_diluted_supply.

Full root cause analysis, architecture rationale, exact invariant change, and empirical proof are in docs/IMPLEMENTATION_REPORTS/v3.6.1-supply-basis-coherence-tolerance.md.

Scope and architecture

  • Governing Issue: Implement canonical valuation methodology (ADR 0022) #107 (Milestone 1, indirectly — this fixes a canonical model gap surfaced by that milestone's real acquisition, not Milestone 1 work itself).
  • Architecture Impact Check: SupplyBasisSnapshot.__post_init__'s total<=fully_diluted check is relaxed to a tolerance-based, non-rejecting policy (raw values always persisted verbatim; conflict_state="open" surfaces gaps beyond a small entity/provider-agnostic tolerance instead of silently accepting or hard-rejecting). No other coherence check in the same model was touched.
  • Evidence Impact: none — no evidence semantics changed; this is a supply-basis-only fix.
  • No unapproved scope expansion — narrowly scoped to the one check with a demonstrated real-data failure.
  • ADR 0022 authority boundaries, append-only correction semantics, and strict-known replay guarantees are unchanged; no service/repository/authorization logic was touched, only the record's own validation.

Acceptance-criteria matrix

Acceptance criterion Status Evidence
Model can represent real provider observations where max_supply < total_supply PASS Report "Proof" section: direct SupplyBasisSnapshot(...) construction with Sky's exact real CoinGecko values succeeds, no exception
Raw provider values never overwritten/clamped/fabricated PASS quantity_components stores caller-supplied values verbatim in both the within-tolerance and beyond-tolerance test cases
Full provenance preserved PASS observed_market_fact_ids/evidence_record_ids unchanged, no new required fields
Precision/timing-scale violations persist as accepted PASS test_supply_basis_accepts_total_above_fully_diluted_within_precision_tolerance
True contradictions surfaced via conflict metadata, not discarded PASS test_supply_basis_flags_conflict_when_total_exceeds_fully_diluted_beyond_tolerance
Entity-agnostic, no Sky special-casing PASS SUPPLY_COHERENCE_RELATIVE_TOLERANCE is a flat constant applied uniformly; no entity/provider name anywhere in the check
Existing persisted records remain replay-compatible PASS Every previously-accepted record already satisfied the strict form of this check; relaxing it cannot invalidate existing data. No schema/migration change.
Full quality gates pass PASS See Verification below
  • No criterion omitted or inferred from green CI.
  • No FAIL/BLOCKED criterion remains.

Verification

  • ruff check .
  • black --check .
  • python -m mypy
  • Full pytest suite
$ python -m ruff check .
All checks passed!

$ python -m black --check .
All done! ✨ 🍰 ✨
571 files would be left unchanged.

$ python -m mypy
Success: no issues found in 570 source files

$ python -m pytest -q
1139 passed in 472.76s (0:07:52)

Operational validation

Not applicable in the live-acquisition sense — this is a model-layer fix, not an acquisition run. The report's "Proof" section demonstrates, with Sky's exact real observed CoinGecko values (reproduced from the actual failed workflow run's log), that the previously-rejected construction now succeeds. A fresh live acquisition run against the corrected main (via .github/workflows/acquire-sky-supply-basis.yml) is the next step after this merges, to replace PR #110 branch's existing (fully_diluted_supply-omitted) SupplyBasisSnapshot with a complete one.

Remaining limitations and risks

  • SUPPLY_COHERENCE_RELATIVE_TOLERANCE = 0.0001 is a considered policy constant, not derived from a formal model of any specific provider's rounding behavior — disclosed in the report's "Known limitations" section.
  • Does not retroactively fix the SupplyBasisSnapshot already persisted on PR Issue #107 Milestone 1: entity-agnostic valuation evidence acquisition (Sky pilot) #110's branch; a fresh acquisition run is required after this merges.

Implementer readiness declaration

  • READY FOR REVIEW

Generated by Claude Code

Root cause: SupplyBasisSnapshot.__post_init__ hard-rejected any
total_supply > fully_diluted_supply, which real CoinGecko data for
Sky violates by a relative gap of ~2.8e-12 (provider rounding, not a
real economic contradiction). The only prior workaround (omitting
fully_diluted_supply entirely, PR #117) was independently flagged as
insufficient: ADR 0022 Scope condition 3 requires all three supply
quantities to be independently observable, and an omitted component
cannot satisfy that.

Replace the hard raise with a tolerance-based policy, mirroring the
existing conflict_state="open" pattern already used elsewhere in this
record family (SupplyAndValueCaptureService._apply_conflict_policy):
raw provider values are always persisted exactly as observed, never
clamped or fabricated; a gap within
SUPPLY_COHERENCE_RELATIVE_TOLERANCE (0.01%, entity/provider-agnostic)
is accepted as ordinary data; a larger gap is not rejected either, but
surfaces via conflict_state="open" instead of silently passing as
"none". No exception is ever raised by this check anymore.

scripts/acquire_sky_supply_basis.py now always includes
fully_diluted_supply when max_supply is observed, since the coherence
policy decision now lives exclusively in the canonical model.

No schema/migration change; every previously-accepted
SupplyBasisSnapshot already satisfied the strict form of this check,
so relaxing it cannot invalidate existing persisted data.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZwAhhLUYJMGgJm9yyzs7H
@fafa33
fafa33 marked this pull request as ready for review July 26, 2026 08:41

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90de0a2a57

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/hunter/value_capture/models.py
…erence

Independent review (Codex) on this same PR found the first version of
this fix left a bypass: it only forced conflict_state="open" when the
caller supplied "none", so an initial record (no
supersedes_record_id) could self-declare "resolved" for a
beyond-tolerance total>fully_diluted gap and pass straight through
strict_known_supply/strict_known_evidence's {"none", "resolved"}
eligibility check, since _authorize_correction only runs authority
checks when a correction predecessor exists.

An initial record has no prior, authority-checked correction that
could legitimately have resolved anything, so conflict_state is now
forced to "open" unconditionally in that case, regardless of what the
payload claims. Only a correction (already gated by
_authorize_correction's source-tier transition check) may supply an
explicit non-"none" conflict_state that is respected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZwAhhLUYJMGgJm9yyzs7H
@fafa33
fafa33 merged commit 5265523 into main Jul 26, 2026
1 check passed
@fafa33
fafa33 deleted the fix/supply-coherence-tolerance branch July 26, 2026 09:42
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.

2 participants