Skip to content

Releases: lluvr/frame-check

v1.1.3

Choose a tag to compare

@github-actions github-actions released this 02 Jul 14:11
  • The divergence block no longer reports retired or meta-side (n/a)
    frames as absent_frames. A retired detector or a meta-side frame with
    no text-side rule can never fire on a document, so surfacing it as a
    document-level absence was a phantom absence an agent could not act on
    (e.g. FVS-001, retired, previously appeared with signal_strength: high). Such frames remain available as library vocabulary via the
    resources; only active-detection frames now appear as absences.
  • Re-synced the packaged data staged under framecheck_mcp/ with the
    canonical data/ tree (frame-library detection index and worked-example
    outputs). The build already re-stages fresh, so shipped wheels were
    correct; this fixes the stale committed copies that dev-tree reads and
    a staging-skipped build would otherwise see.

v1.1.2

Choose a tag to compare

@github-actions github-actions released this 02 Jul 08:28
  • Coverage attribution now reports markers_unattributed on each coverage
    dimension: markers that are counted but cannot be mapped to a sentence
    (short sentences and headings the tokenizer drops) are surfaced so the
    headline count and the cited sentence_matches reconcile, rather than
    the difference vanishing silently. Additive output field.

  • The bundled worked-example outputs and the frame-library detection index
    were reconciled with the shipped detector state: the retired FVS-001
    detection rule no longer appears in worked-example frame_matches, and
    FVS-008 / FVS-015 are marked active. Bundled data only; the LLM response
    text and the detector code are unchanged.

  • Temporal orientation no longer mislabels a document with tied past and
    future markers as present-oriented at 0% present. The dominant tense is
    now the actual most-frequent tense; the balanced flag (dominant_margin
    == 0) conveys the tie.

  • Coverage analysis on punctuation-sparse input is no longer quadratic in
    document length. The forward diminisher window is bounded before the
    search runs, closing a denial-of-service vector on the MCP path
    (documents up to 1,000,000 chars). Detector output is unchanged.

  • The cross-model comparison verdict no longer contradicts itself when two
    responses share a frame at different signal densities. It now recognizes
    the shared frame by identity instead of naming the same frame twice and
    then asserting the two measure different things.

v1.1.1

Choose a tag to compare

@github-actions github-actions released this 02 Jun 11:15

frame-check-mcp v1.1.1

  • The citation string in every tool response (provenance.citation) and
    in the two bundled worked-example outputs titled Frame Check "a research
    instrument for framing and verification in documents." It now reads "a
    structural framing analysis tool," matching the project description and
    README. Citation text only: no API, schema, or behavior change.

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 07:46

Frame Check 1.1.0

Non-breaking release. Import surface, MCP tool/resource surface, and all
wire-payload field names + structure are unchanged; 1.0.x adopters
upgrade with no code changes.

  • Repository moved to the personal account: github.com/lluvr/frame-check (public).
  • Dropped the canon-as-product positioning (the methodology-canon framing
    and dead lodestone pointers); methodology now at
    frame.clarethium.com/corpus/methodology.
  • src-layout packaging (top-level import surface unchanged).
  • De-shipped the research/validation apparatus from the bundle.
  • agent_guidance wire text reworded (sovereignty / Phase-2 framing dropped);
    field names and values unchanged.
  • Doc refinements; em-dash sweep; CI src-layout fixes.

See docs/CHANGELOG.md [1.1.0] for the full list.

v1.0.12

Choose a tag to compare

@github-actions github-actions released this 11 May 19:15

[1.0.12] - 2026-05-11

Schema coherence: full canonical URI/URL quartet on every frame-reference shape

Closes the schema-coherence backlog opened at v1.0.10/v1.0.11.
Fresh-eyes audit on the v1.0.11 baseline surfaced two remaining
instances of the same defect class:

  • frame_opportunities[*] (opt-in LLM-composed teaching
    questions): emitted only citation_uri for the MCP resource
    URI; missing library_resource_uri (decision_readiness
    convention) and the library_url/public_url pair entirely.
  • decision_readiness.dimensions[*].library_entries[*] (and
    fired_library_entries[*]): emitted only library_resource_uri
    • public_url; missing the citation_uri and library_url
      aliases used by the absent_frames + typical_co_* blocks.
  • divergence.absent_frames[*] and corpus_context.typical_co_*:
    emitted citation_uri + library_resource_uri + library_url, but
    missing public_url.
  • frame_library_matches[*]: emitted library_resource_uri +
    library_url, but missing citation_uri and public_url.

Every frame-reference record across the payload now carries the
full canonical quartet {citation_uri, library_resource_uri, library_url, public_url} where:

  • citation_urilibrary_resource_uri (both point to the
    frame-check://library/<fvs_id> MCP resource)
  • library_urlpublic_url (both point to the same HTTPS
    GitHub URL for the entry markdown, or both are None when the
    entry has no canonical filename)

An adopter writing a single FVS-reference renderer can now read
the same field shape regardless of which payload block they're
parsing. Pre-v1.0.12 integrations that used only one alias name
per pair remain valid; the additive aliases are forever.

Code sites edited:

  • decision_readiness.py:170-185 (library_entry_ref)
  • mcp_compose.py:1291-1320 (absent_frames)
  • mcp_compose.py:2607-2640 (frame_check
    frame_library_matches)
  • mcp_compose.py:3498-3530 (frame_compare
    frame_library_matches)
  • corpus_intelligence.py:447-470 (typical_co_fires + absences)
  • frame_opportunities.py:265-289 (frame_opportunities[*])

Pinned by
tests/test_mcp_server.py::test_all_frame_reference_shapes_carry_canonical_uri_url_quartet:
walks the payload, finds every dict with fvs_id or frame_id
matching the FVS- prefix, asserts the quartet on each, asserts
the alias-equality invariant. Verified on 19 distinct FVS IDs
across all 5 emit sites in the bundled Grok-NVIDIA fixture.

Snapshot refreshed.

Deferred from this round (with rationale)

The wider field-name pairs nametitle and fvs_id
frame_id remain divergent across blocks:

  • nametitle: NOT semantically equivalent.
    frame_library_matches[*].name carries an absence-qualifier
    (e.g., 'Failure Framing (absent)') when the frame fires as
    absence-pattern; title is canonical without qualifier.
    Naive aliasing would conflate distinct content. Operator
    decision required.
  • fvs_idframe_id: same value in current data, safe to
    alias mechanically. Deferred — the frame_id rename in
    particular touches more integrations than the URI/URL pair
    and warrants explicit consideration.

v1.0.11

Choose a tag to compare

@github-actions github-actions released this 11 May 18:54

[1.0.11] - 2026-05-11

Schema alignment: library_resource_uri on corpus_context.typical_co_fires / typical_co_absences

Same defect class as the v1.0.10 fix on divergence.absent_frames[*],
discovered at a different emit site by a fresh-eyes schema-coherence
audit on the v1.0.10 baseline. The corpus_context.typical_co_fires
and corpus_context.typical_co_absences records (under both
frame_library_matches[*] and divergence.absent_frames[*]) carried
only citation_uri for the MCP resource URI; not the
library_resource_uri field that the parallel
decision_readiness.dimensions[*].library_entries[*] block emits.
An MCP-integrated agent that learned the decision_readiness shape
and looked for library_resource_uri on co_fires per analogy got
nothing.

This release adds library_resource_uri to both blocks at the
corpus_intelligence.py:438,447 emit site. Both fields carry
identical frame-check://library/<fvs_id> values; pre-1.0.11
integrations using citation_uri keep working. Schema-additive
only.

Pinned by
tests/test_mcp_server.py::test_typical_co_fires_carry_library_resource_uri:
asserts the field exists on every typical_co_* record, matches
expected URI shape, and equals citation_uri.

Snapshot refresh on the bundled Grok-NVIDIA worked example so the
worked-example regression test continues to pass against the new
wire shape.

Deferred from this round (with rationale)

The fresh-eyes audit also surfaced wider field-name divergence
across blocks: name vs title vs frame_title for the human-
readable label; library_url vs public_url for the GitHub URL;
fvs_id vs frame_id for the identifier. Aliasing was NOT
applied across the board:

  • library_urlpublic_url: byte-identical values in current
    data. Safe to alias mechanically. Deferred pending a deliberate
    schema decision (additive aliases are forever; the choice
    shouldn't be rushed).
  • fvs_idframe_id: same value. Safe to alias.
  • nametitle: NOT semantically equivalent.
    frame_library_matches[*].name carries an absence-qualifier
    suffix (e.g., 'Failure Framing (absent)') when the frame
    detects as absence-pattern; title is canonical without
    qualifier. Naive aliasing would conflate distinct content.

These three non-fixed items are tracked as schema-coherence
backlog; v1.0.11 closes only the library_resource_uri instance
because that fix matches the v1.0.10 pattern exactly with no
semantic risk.

v1.0.10

Choose a tag to compare

@github-actions github-actions released this 11 May 18:15

[1.0.10] - 2026-05-11

Schema alignment: library_resource_uri on divergence.absent_frames

Operator Phase-2 client validation surfaced an MCP schema
inconsistency. decision_readiness.dimensions[*].library_entries[*]
emits frame references with the shape
{fvs_id, library_resource_uri, public_url} (see
decision_readiness.py:167-174). divergence.absent_frames[*]
emitted the parallel concept under different field names:
{frame_id, citation_uri, library_url}. An MCP-integrated agent
that learned the decision_readiness shape and looked for
library_resource_uri on absent_frames per analogy got None.

The cross-block inconsistency was load-bearing in practice: the
v1.0.9 Phase-2 protocol document (Test 2 — Frame Divergence)
asked Claude Desktop to cite absent frames by library_resource_uri
per the decision_readiness convention; the operator's client run
found the field absent on absent_frames and surfaced this
correctly.

This release adds library_resource_uri to absent_frames
records as an alias for citation_uri. Both fields carry
identical values
(frame-check://library/<frame_id>); pre-v1.0.10 integrations
using citation_uri remain valid. Schema-additive only — no
fields renamed or removed.

Pinned by
tests/test_mcp_server.py::test_absent_frames_carry_library_resource_uri:
asserts the field exists on every absent_frame, matches the
expected URI shape, and equals the existing citation_uri. A
future composer change that drops the alias fails the test.

The parallel frame_idfvs_id and library_urlpublic_url
field-name pairs remain divergent across blocks; promoting either
of those to alias-pair status is a separate decision (the
frame_id rename in particular would touch more integrations
and is deferred pending adopter feedback).

v1.0.9

Choose a tag to compare

@github-actions github-actions released this 11 May 15:40

[1.0.9] - 2026-05-11

Source-fidelity diagnostics: per-claim unsourced_items

The source-fidelity ratio (Layer 4: digit-substring match of a
document's numbers against the source it was supposed to be
grounded in) is the capability that distinguishes Frame Check
from framing-only tools. Pre-v1.0.9, the wire format reported
the COUNT of unsourced numbers
(source_fidelity.not_in_source: 2 out of 25) but not WHICH
specific numbers. Adopters reading "23/25 in source" got the
headline but couldn't act on the 8% unsourced rate without
manually diffing source vs. summary side-by-side — which
defeats the tool's purpose for AI-output auditing.

The internal data was already computed:
clarethium_measure.source_matching() builds
unsourced_details as [{value, type, context}, ...] where
context is the claim-sentence the number appeared in
(clarethium_measure.py:843-846). The MCP composer at
mcp_compose.py:2708 was reading the summary fields and
dropping the items list.

This release surfaces verification.source_fidelity.unsourced_items
on the wire when source_text is provided. Adopters now see:

{"value": "100000000", "type": "integer",
 "context": "NVIDIA RTX now serves 100 million gamers..."}

against the load-bearing demo (Grok-on-NVIDIA worked example):
the LLM smuggled a "100 million users" figure from training data
into a summary of a press release that disclosed no user count.
That class of insertion is exactly what the source-fidelity
capability exists to surface; the headline ratio is necessary
but not sufficient — the per-claim diagnostic is the actionable
half.

Wire-format addition only (no removed or renamed fields). The
new field is omitted when no source_text is supplied (same
schema-stability discipline as the rest of the verification
block). Pinned by
tests/test_mcp_server.py::test_source_fidelity_carries_per_claim_unsourced_items.

v1.0.8

Choose a tag to compare

@github-actions github-actions released this 11 May 13:18

[1.0.8] - 2026-05-11

Same-class fix: git_sha=unknown in version banner

The v1.0.7 cut closed three manifest-block fields with broken
__file__-relative data lookups (pipeline_version,
frame_library_version, sn_corpus). Phase-1 e2e against the live
v1.0.7 wheel surfaced a fourth field with the same root cause:
mcp_server.py:_install_version_info has its own SHA detection
chain (separate from version.py:_detect_pipeline_version) that
also reads pipeline_version.txt from _SCRIPT_DIR only — so
frame-check-mcp --version reports git_sha=unknown on every
fresh-venv install, even though the manifest field now reports
the correct SHA.

Cosmetically minor (the wire-format manifest carries the correct
SHA), but adopter-facing: the version banner is the first thing
an adopter runs after install, and seeing git_sha=unknown
undermines confidence in the install. Same dual-path fix as
v1.0.7: probe both _SCRIPT_DIR/pipeline_version.txt and
_SCRIPT_DIR/framecheck_mcp/pipeline_version.txt.

CI hardening: the publish.yml smoke step now captures the
frame-check-mcp --version output and fails if it contains
git_sha=unknown. Closes the bug class on the version-banner
surface alongside the manifest-field assertions added at v1.0.7.

Note on duplication: mcp_server.py and version.py carry
parallel SHA-detection chains by design — mcp_server.py runs
git-rev-parse first (so dev always sees the current commit, not
the last baked SHA), while version.py:PIPELINE_VERSION checks
env var → baked file → git in that order (so production reads
the build-time SHA before falling back to git, since _SCRIPT_DIR
in a wheel install has no .git directory). Consolidating into
one helper would invert the dev-mode precedence and risk a
silent staleness regression. Two parallel fixes is the right
shape.

v1.0.7

Choose a tag to compare

@github-actions github-actions released this 11 May 12:25

[1.0.7] - 2026-05-11

Production manifest self-reporting was broken in three fields

A fresh-venv install + neutral-cwd smoke (the discipline the v1.0.6
publish step did not exercise) surfaced three manifest fields the
production wheel had been emitting wrong since v1.0.0:

  • manifest.pipeline_version: 'unknown' (expected: short git SHA
    of the commit that built the wheel)
  • manifest.frame_library_version: '0.0.0' (expected: the
    library version pinned in data/frame_library/VERSION)
  • manifest.sn_corpus.version: 'unknown', size: 0, seeded_at:
    'unknown' (expected: values from
    calibration/source_network_corpus.yaml)

Same root cause for all three: the loader functions in version.py
and manifest.py resolve data files via
Path(__file__).resolve().parent / "...". In the source tree the
data lives next to the modules at the repo root, so the lookup
works in dev. The wheel layout is different: the modules install
as top-level py-modules at /site-packages/, while
pyproject [tool.setuptools.package-data] bundles the data inside
/site-packages/framecheck_mcp/. The single-path __file__-
relative lookup misses the framecheck_mcp/ subpackage every time.

mcp_server.py:_DATA_ROOT and frame_library_index.py:_DATA_ROOT
already had a dual-path probe for exactly this reason
(documented in the comment headers). version.py and manifest.py
were never updated to follow the same pattern, so adopters'
manifests have been quietly missing self-reporting since v1.0.0.

Fix is mechanical:

  • version.py:_detect_pipeline_version(): probe both
    pipeline_version.txt next to version.py AND inside
    framecheck_mcp/.
  • manifest.py:_frame_library_version(): probe both
    data/frame_library/VERSION next to manifest.py AND inside
    framecheck_mcp/data/frame_library/.
  • manifest.py:_calibration_corpus(): probe both
    calibration/source_network_corpus.yaml locations.
  • pyproject.toml [tool.setuptools.package-data]: add
    calibration/source_network_corpus.yaml to the framecheck_mcp
    package-data list (was unbundled entirely, so even with the
    lookup fix the file would not have been findable in the
    wheel).

CI hardening: the publish.yml Smoke-test installed wheel step
now cd /tmp before importing (previously it ran from the
checkout directory, which shadowed the installed wheel with the
source tree and let the bug class hide), and asserts the three
manifest fields are non-default. A regression of the same
file-relative lookup shape now fails CI loudly at publish
time instead of shipping silently. Verified end-to-end locally
before the v1.0.7 cut: build + install in fresh venv + run from
neutral cwd; all three fields populated.

Wire format unchanged at the field-name level (the same fields
that existed before now carry correct values instead of
fallbacks). Adopters who depended on the fallback values
specifically will see a one-time change at v1.0.7 install; this
is the intent.