Six-skill presentation system: ingest talks into a rhetoric vault, run interactive clarification, generate a speaker profile, create presentations that match your documented patterns, produce the deck illustrations + thumbnail visual layer, and publish talk pages to a Jekyll shownotes site. Includes a 111-entry Presentation Patterns taxonomy (81 observable: 62 patterns + 19 antipatterns; 30 unobservable: 21 patterns + 9 antipatterns) for scoring, brainstorming, and go-live preparation.
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
"""Deterministic talk-identity assessment for candidate PPTX decks.
A deck becomes evidence for whichever talk the catalog says it belongs to. That
binding is made once, before persistence, and every later safeguard runs after
it — so a deck bound to the wrong talk supplies slide counts, design evidence,
OCR, and pattern observations to that wrong talk with nothing downstream able to
notice.
This module proves the binding instead of assuming it. It reads deterministic
identity facts already present on both sides — the catalog's title, conference,
and delivery date; the deck's path, document properties, and rendered title,
footer, and hashtag text — and reports which talk the deck belongs to, or
refuses to choose.
Two rules shape the taxonomy:
* Filename similarity alone never selects a talk. Reused talk families and
nearby years produce near-identical filenames, which is precisely the signal
that mis-assigned the live vault's decks in the first place.
* An unproven binding is a review finding, never a silent match. Refusing to
choose costs one owner decision; choosing wrongly corrupts every derived
analysis for that talk until someone notices.
Title and event comparison delegate to `source_identity_matching`, the same
authority the video source-identity audit uses. A deck must not be matched by a
weaker parallel rule than a recording.
"""
from __future__ import annotations
import posixpath
import re
from dataclasses import dataclass, field
from typing import Any, Iterable, Mapping, Sequence, TypeGuard
from source_identity_matching import (
AMBIGUOUS_EVENT_ALIASES,
EventAlias,
YEAR_RE,
event_alias,
event_aliases_compatible,
known_event_aliases,
normalized_words,
titles_agree,
)
# v2 binds the assessment to the deck GENERATION it was made against, not just
# to the deck's path. v1 compared `assessment["pptx_path"]` to the row's path,
# so replacing the file at that path left the `matched` verdict standing and the
# new deck's slides, OCR and pattern observations became that talk's evidence
# under a proof made about different bytes — the #176 failure surviving its own
# fix. A v1 assessment cannot be upgraded in place: nothing recorded which bytes
# it read, so it falls to `identity_assessment_schema_unsupported` and reads as
# unproven, the same position `unassessed_legacy_binding` takes for the same
# reason (a proof not witnessed cannot be manufactured).
PPTX_TALK_IDENTITY_SCHEMA_VERSION = 2
# Signal verdicts. `unknown` is the honest default: a fact the deck does not
# carry is not evidence for or against any candidate.
SIGNAL_AGREE = "agree"
SIGNAL_CONFLICT = "conflict"
SIGNAL_UNKNOWN = "unknown"
SIGNAL_VERDICTS = frozenset({SIGNAL_AGREE, SIGNAL_CONFLICT, SIGNAL_UNKNOWN})
# Signal names, in report order.
SIGNAL_TITLE = "title"
SIGNAL_VENUE = "venue"
SIGNAL_DELIVERY_YEAR = "delivery_year"
SIGNAL_HASHTAG = "hashtag"
SIGNAL_PUBLISHED_PDF = "published_pdf"
SIGNAL_FILENAME_SIMILARITY = "filename_similarity"
SIGNAL_NAMES = (
SIGNAL_TITLE,
SIGNAL_VENUE,
SIGNAL_DELIVERY_YEAR,
SIGNAL_HASHTAG,
SIGNAL_PUBLISHED_PDF,
SIGNAL_FILENAME_SIMILARITY,
)
# A selecting signal must be one a same-family deck from another delivery could
# not also satisfy. Two signals are deliberately excluded:
#
# * filename similarity — reused talk families produce near-identical filenames,
# which is what mis-assigned the live vault's decks in the first place;
# * delivery year — every talk delivered that year satisfies it equally, so it
# narrows a candidate set without identifying anything in it.
#
# Both still report, and a year MISmatch still contradicts. Vetoing and electing
# are separate powers: a wrong year is proof of the wrong delivery, while a
# right year is proof of nothing.
SELECTING_SIGNALS = frozenset(
{
SIGNAL_TITLE,
SIGNAL_VENUE,
SIGNAL_HASHTAG,
SIGNAL_PUBLISHED_PDF,
}
)
VERDICT_MATCHED = "matched"
VERDICT_REVIEW_REQUIRED = "review_required"
VERDICT_UNMATCHED = "unmatched"
VERDICTS = frozenset({VERDICT_MATCHED, VERDICT_REVIEW_REQUIRED, VERDICT_UNMATCHED})
REASON_NO_CANDIDATE_TALKS = "identity_no_candidate_talks"
REASON_NO_AGREEING_SIGNAL = "identity_no_agreeing_signal"
REASON_FILENAME_SIMILARITY_ONLY = "identity_filename_similarity_only"
REASON_AMBIGUOUS_CANDIDATES = "identity_ambiguous_candidates"
REASON_CONFLICTING_SIGNALS = "identity_conflicting_signals"
REASON_MATCHED = "identity_matched"
REASON_NON_DELIVERY_ARTIFACT = "identity_non_delivery_artifact"
# Stamped by migration onto a record that bound its talk before any assessment
# existed. The binding is not declared wrong — it is declared unproven, which is
# the honest reading and the one that routes it to review instead of trusting it.
REASON_UNASSESSED_LEGACY_BINDING = "identity_unassessed_legacy_binding"
# The deck could not be observed at refusal time, so the stored generation could
# not be compared to anything. Distinct from a mismatch: "we looked and it
# differs" and "we could not look" are different findings, and collapsing them
# would let an unreadable deck read as a passing comparison.
REASON_SOURCE_UNOBSERVABLE = "identity_source_unobservable"
# The assessment names a different generation of this deck than the one on disk.
REASON_GENERATION_STALE = "identity_generation_stale"
REASON_CODES = frozenset(
{
REASON_NO_CANDIDATE_TALKS,
REASON_NO_AGREEING_SIGNAL,
REASON_FILENAME_SIMILARITY_ONLY,
REASON_AMBIGUOUS_CANDIDATES,
REASON_CONFLICTING_SIGNALS,
REASON_MATCHED,
REASON_NON_DELIVERY_ARTIFACT,
REASON_UNASSESSED_LEGACY_BINDING,
}
)
# The only reason a `matched` verdict may claim. Every other code in the
# taxonomy explains a refusal, so pairing one with `matched` describes an
# assessment that cannot exist — most dangerously the legacy-binding code, which
# means the opposite of proven.
MATCHED_REASON_CODES = frozenset({REASON_MATCHED})
# An editable master and a published static export are legitimate artifacts for
# a delivery, but they are not the delivery deck and must not silently become
# its evidence. Roles are reported so the owner records which artifact is the
# published source and which is a later or editable variant.
ROLE_DELIVERY = "delivery"
ROLE_MASTER = "master"
ROLE_STATIC_EXPORT = "static_export"
ROLE_BACKUP = "backup"
ARTIFACT_ROLES = frozenset(
{ROLE_DELIVERY, ROLE_MASTER, ROLE_STATIC_EXPORT, ROLE_BACKUP}
)
# Matched against whole path tokens, never substrings: `masterclass` is a talk
# topic, `master` is an artifact role.
_ROLE_TOKENS: tuple[tuple[str, frozenset[str]], ...] = (
(
ROLE_BACKUP,
frozenset({"backup", "backups", "bak", "archive", "archived", "old"}),
),
(ROLE_MASTER, frozenset({"master", "masters", "template", "templates", "source"})),
(ROLE_STATIC_EXPORT, frozenset({"static", "export", "exports", "exported"})),
)
_TOKEN_RE = re.compile(r"[^\W_]+", re.UNICODE)
_HASHTAG_RE = re.compile(r"#(\w+)", re.UNICODE)
_TALK_FILENAME_DATE_RE = re.compile(
r"\A(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})-"
)
# A deck whose filename shares this many significant words with a talk's slug is
# similar enough to report — and never, on its own, similar enough to select.
_FILENAME_OVERLAP_MINIMUM = 2
class PptxTalkIdentityError(ValueError):
"""A talk-identity assessment input violates the module's contract."""
@dataclass(frozen=True)
class DeckIdentityFacts:
"""Deterministic identity facts observed on one candidate deck.
Every field beyond `pptx_path` is optional because a damaged or minimal
deck still deserves an assessment from whatever it does carry. Absence
weakens the evidence; it never invents agreement.
"""
pptx_path: str
document_title: str | None = None
document_created_year: str | None = None
rendered_title: str | None = None
rendered_footers: tuple[str, ...] = ()
hashtags: tuple[str, ...] = ()
published_pdf_talk_filename: str | None = None
@property
def path_tokens(self) -> tuple[str, ...]:
return tuple(_TOKEN_RE.findall(self.pptx_path.casefold()))
@property
def basename(self) -> str:
return posixpath.basename(self.pptx_path.replace("\\", "/"))
@dataclass(frozen=True)
class CandidateAssessment:
"""One talk's per-signal standing against the deck under assessment."""
talk_filename: str
signals: Mapping[str, str]
agreeing: tuple[str, ...]
conflicting: tuple[str, ...]
@property
def selectable(self) -> bool:
"""A candidate is selectable on corroboration with no contradiction."""
return bool(self.agreeing) and not self.conflicting
def as_json(self) -> dict[str, Any]:
return {
"talk_filename": self.talk_filename,
"signals": {name: self.signals[name] for name in SIGNAL_NAMES},
"agreeing": list(self.agreeing),
"conflicting": list(self.conflicting),
}
def derive_candidate_standing(
signals: Mapping[str, str],
) -> tuple[tuple[str, ...], tuple[str, ...]]:
"""Derive `(agreeing, conflicting)` from a candidate's per-signal map.
One rule, used by the producer that writes a candidate and by the owner gate
that later reads one back. A stored candidate's arrays are a summary of its
signal map, so a gate that trusts the summary without recomputing it accepts
any pair of values a caller cares to put there — `agreeing: ["venue"]` over a
signal map where venue conflicts, or over no venue reading at all.
Only selecting signals can corroborate; every signal can contradict.
"""
agreeing = tuple(
name
for name in SIGNAL_NAMES
if name in SELECTING_SIGNALS and signals.get(name) == SIGNAL_AGREE
)
conflicting = tuple(
name for name in SIGNAL_NAMES if signals.get(name) == SIGNAL_CONFLICT
)
return agreeing, conflicting
@dataclass(frozen=True)
class TalkIdentityAssessment:
"""The full, schema-versioned identity verdict for one deck."""
pptx_path: str
verdict: str
artifact_role: str
selected_talk_filename: str | None
reason_codes: tuple[str, ...]
# The deck generation this verdict was reached against. `None` means the
# deck could not be digested at assessment time; the verdict still records
# what the facts showed, and `binding_refusal` refuses to authorize a
# binding it cannot pin to bytes.
source_identity: Mapping[str, Any] | None = None
candidates: tuple[CandidateAssessment, ...] = field(default=())
@property
def matched(self) -> bool:
return self.verdict == VERDICT_MATCHED
@property
def review_required(self) -> bool:
return self.verdict == VERDICT_REVIEW_REQUIRED
def as_json(self) -> dict[str, Any]:
return {
"schema_version": PPTX_TALK_IDENTITY_SCHEMA_VERSION,
"pptx_path": self.pptx_path,
"verdict": self.verdict,
"artifact_role": self.artifact_role,
"selected_talk_filename": self.selected_talk_filename,
"reason_codes": list(self.reason_codes),
"source_identity": (
dict(self.source_identity) if self.source_identity is not None else None
),
"candidates": [candidate.as_json() for candidate in self.candidates],
}
def _require_text(value: object, label: str) -> str:
if not isinstance(value, str) or not value.strip():
raise PptxTalkIdentityError(f"{label} must be a non-empty string")
return value
def _optional_text(value: object, label: str) -> str | None:
if value is None:
return None
if not isinstance(value, str):
raise PptxTalkIdentityError(f"{label} must be a string or null")
stripped = value.strip()
return stripped or None
def _text_tuple(value: object, label: str) -> tuple[str, ...]:
if value is None:
return ()
if isinstance(value, str) or not isinstance(value, Sequence):
raise PptxTalkIdentityError(f"{label} must be an array of strings")
items: list[str] = []
for index, item in enumerate(value):
text = _optional_text(item, f"{label}[{index}]")
if text is not None:
items.append(text)
return tuple(items)
def deck_identity_facts(value: object) -> DeckIdentityFacts:
"""Validate a caller-supplied deck fact mapping into the closed shape.
Typed `object` deliberately: this is the boundary where unvalidated caller
input becomes a closed shape, so the isinstance guard is the contract, not
a redundant assertion behind a narrower annotation.
"""
if not isinstance(value, Mapping):
raise PptxTalkIdentityError("deck facts must be a mapping")
unknown = set(value) - {
"pptx_path",
"document_title",
"document_created_year",
"rendered_title",
"rendered_footers",
"hashtags",
"published_pdf_talk_filename",
}
if unknown:
raise PptxTalkIdentityError(f"deck facts carry unknown keys: {sorted(unknown)}")
created_year = _optional_text(
value.get("document_created_year"), "deck facts document_created_year"
)
if created_year is not None and not re.fullmatch(r"(?:19|20)\d{2}", created_year):
raise PptxTalkIdentityError(
"deck facts document_created_year must be a four-digit year"
)
return DeckIdentityFacts(
pptx_path=_require_text(value.get("pptx_path"), "deck facts pptx_path"),
document_title=_optional_text(
value.get("document_title"), "deck facts document_title"
),
document_created_year=created_year,
rendered_title=_optional_text(
value.get("rendered_title"), "deck facts rendered_title"
),
rendered_footers=_text_tuple(
value.get("rendered_footers"), "deck facts rendered_footers"
),
hashtags=_text_tuple(value.get("hashtags"), "deck facts hashtags"),
published_pdf_talk_filename=_optional_text(
value.get("published_pdf_talk_filename"),
"deck facts published_pdf_talk_filename",
),
)
def classify_artifact_role(facts: DeckIdentityFacts) -> str:
"""Report whether the deck is a delivery artifact or a variant of one."""
tokens = set(facts.path_tokens)
for role, markers in _ROLE_TOKENS:
if tokens & markers:
return role
return ROLE_DELIVERY
def _talk_year(talk: Mapping[str, Any]) -> str | None:
"""Resolve a talk's delivery year from its date, else its filename prefix.
Both are recorded values. Neither consults the clock, so an assessment made
today and the same assessment made next year agree.
"""
date_value = talk.get("date")
if isinstance(date_value, str):
match = YEAR_RE.search(date_value)
if match is not None:
return match.group(0)
filename = talk.get("filename")
if isinstance(filename, str):
match = _TALK_FILENAME_DATE_RE.match(filename)
if match is not None:
return match.group("year")
return None
def _deck_path_years(facts: DeckIdentityFacts) -> tuple[str, ...]:
return tuple(
token
for token in facts.path_tokens
if re.fullmatch(r"(?:19|20)\d{2}", token) is not None
)
def _deck_venue_aliases(
facts: DeckIdentityFacts, known_aliases: frozenset[EventAlias]
) -> list[EventAlias]:
"""Read venue aliases from the deck's directory components.
Only directories are consulted. A deck's own filename is the talk's name far
more often than the venue's, and reading a venue out of it would manufacture
agreement from the one signal this module refuses to trust alone.
A component counts as a venue claim only when it names an event some talk in
the vault actually uses. Without that gate every generic folder — `Decks/`,
`Downloads/` — would parse as an unrecognized venue and contradict every
candidate, turning the discriminator into a blanket refusal.
"""
normalized = facts.pptx_path.replace("\\", "/")
components = [part for part in posixpath.dirname(normalized).split("/") if part]
aliases: list[EventAlias] = []
for component in components:
alias = event_alias(component)
if alias is None:
continue
if len(alias) == 1 and alias[0] in AMBIGUOUS_EVENT_ALIASES:
# `devops/` names a topic folder at least as often as an event.
continue
if not any(event_aliases_compatible(alias, known) for known in known_aliases):
continue
aliases.append(alias)
return aliases
def _title_signal(
facts: DeckIdentityFacts,
talk: Mapping[str, Any],
_known_aliases: frozenset[EventAlias],
) -> str:
talk_title = talk.get("title")
if not isinstance(talk_title, str) or not talk_title.strip():
return SIGNAL_UNKNOWN
observed = [
text
for text in (
facts.document_title,
facts.rendered_title,
*facts.rendered_footers,
)
if text
]
if not observed:
return SIGNAL_UNKNOWN
if any(titles_agree(talk_title, text) for text in observed):
return SIGNAL_AGREE
# A deck legitimately carries a punchier title than its catalog entry, so a
# non-agreeing title is missing corroboration rather than contradiction.
return SIGNAL_UNKNOWN
def _venue_signal(
facts: DeckIdentityFacts,
talk: Mapping[str, Any],
known_aliases: frozenset[EventAlias],
) -> str:
talk_alias = event_alias(talk.get("conference"))
if talk_alias is None:
return SIGNAL_UNKNOWN
deck_aliases = _deck_venue_aliases(facts, known_aliases)
if not deck_aliases:
return SIGNAL_UNKNOWN
if any(event_aliases_compatible(talk_alias, alias) for alias in deck_aliases):
return SIGNAL_AGREE
# The deck sits under a named event that is not this talk's event. That is
# the discriminator between two deliveries of one reused talk.
return SIGNAL_CONFLICT
def _delivery_year_signal(
facts: DeckIdentityFacts,
talk: Mapping[str, Any],
_known_aliases: frozenset[EventAlias],
) -> str:
talk_year = _talk_year(talk)
if talk_year is None:
return SIGNAL_UNKNOWN
path_years = _deck_path_years(facts)
if path_years:
if talk_year in path_years:
return SIGNAL_AGREE
return SIGNAL_CONFLICT
if facts.document_created_year is not None:
if facts.document_created_year == talk_year:
return SIGNAL_AGREE
# A master edited or re-saved years later is normal, so a document
# timestamp corroborates but never contradicts.
return SIGNAL_UNKNOWN
return SIGNAL_UNKNOWN
def _hashtag_signal(
facts: DeckIdentityFacts,
talk: Mapping[str, Any],
known_aliases: frozenset[EventAlias],
) -> str:
talk_alias = event_alias(talk.get("conference"))
if talk_alias is None or not facts.hashtags:
return SIGNAL_UNKNOWN
# `#VoxxedTicino` carries no word boundary, so a compact comparison against
# the joined alias recovers what alias-wise compatibility cannot see.
compact_talk = "".join(talk_alias)
for raw in facts.hashtags:
for token in _HASHTAG_RE.findall(raw) or [raw.lstrip("#")]:
alias = event_alias(token)
if alias is None:
continue
if event_aliases_compatible(talk_alias, alias):
return SIGNAL_AGREE
if "".join(alias) == compact_talk:
return SIGNAL_AGREE
# Conference hashtags are inconsistently present and frequently abbreviated
# beyond alias recovery, so absence of agreement proves nothing.
return SIGNAL_UNKNOWN
def _published_pdf_signal(
facts: DeckIdentityFacts,
talk: Mapping[str, Any],
_known_aliases: frozenset[EventAlias],
) -> str:
if facts.published_pdf_talk_filename is None:
return SIGNAL_UNKNOWN
filename = talk.get("filename")
if not isinstance(filename, str) or not filename:
return SIGNAL_UNKNOWN
if facts.published_pdf_talk_filename == filename:
return SIGNAL_AGREE
return SIGNAL_CONFLICT
def _filename_similarity_signal(
facts: DeckIdentityFacts,
talk: Mapping[str, Any],
_known_aliases: frozenset[EventAlias],
) -> str:
filename = talk.get("filename")
if not isinstance(filename, str) or not filename:
return SIGNAL_UNKNOWN
slug = _TALK_FILENAME_DATE_RE.sub("", filename)
slug = re.sub(r"\.md\Z", "", slug)
talk_words = normalized_words(slug.replace("-", " "))
deck_words = normalized_words(posixpath.splitext(facts.basename)[0])
if not talk_words or not deck_words:
return SIGNAL_UNKNOWN
if len(talk_words & deck_words) >= _FILENAME_OVERLAP_MINIMUM:
return SIGNAL_AGREE
return SIGNAL_UNKNOWN
_SIGNAL_EVALUATORS = {
SIGNAL_TITLE: _title_signal,
SIGNAL_VENUE: _venue_signal,
SIGNAL_DELIVERY_YEAR: _delivery_year_signal,
SIGNAL_HASHTAG: _hashtag_signal,
SIGNAL_PUBLISHED_PDF: _published_pdf_signal,
SIGNAL_FILENAME_SIMILARITY: _filename_similarity_signal,
}
def assess_candidate(
facts: DeckIdentityFacts,
talk: Mapping[str, Any],
known_aliases: frozenset[EventAlias] = frozenset(),
) -> CandidateAssessment:
"""Evaluate every signal for one candidate talk.
`known_aliases` is the vault's vocabulary of real event names. It defaults
to empty so a single-candidate caller still gets an assessment; the effect
of an empty vocabulary is that no directory reads as a venue, which loses
the signal rather than inventing one.
"""
filename = talk.get("filename")
if not isinstance(filename, str) or not filename:
raise PptxTalkIdentityError("candidate talk requires a filename")
signals = {
name: evaluator(facts, talk, known_aliases)
for name, evaluator in _SIGNAL_EVALUATORS.items()
}
agreeing, conflicting = derive_candidate_standing(signals)
return CandidateAssessment(
talk_filename=filename,
signals=signals,
agreeing=agreeing,
conflicting=conflicting,
)
def assess_pptx_talk_identity(
deck: Mapping[str, Any] | DeckIdentityFacts,
candidates: Iterable[Mapping[str, Any]],
*,
source_identity: Mapping[str, Any] | None = None,
) -> TalkIdentityAssessment:
"""Decide which talk a deck belongs to, or refuse to decide.
The verdict is `matched` only when exactly one candidate is corroborated by
a signal filename similarity cannot fake and contradicted by none. Every
other outcome is `review_required` or `unmatched`; neither authorizes
catalog persistence or extraction.
"""
facts = deck if isinstance(deck, DeckIdentityFacts) else deck_identity_facts(deck)
artifact_role = classify_artifact_role(facts)
talks = list(candidates)
# The candidate set is the vault's event vocabulary. A directory naming an
# event no talk uses is a folder, not a contradicting venue.
known_aliases = frozenset(known_event_aliases(talks))
assessments = tuple(assess_candidate(facts, talk, known_aliases) for talk in talks)
seen: set[str] = set()
for assessment in assessments:
if assessment.talk_filename in seen:
raise PptxTalkIdentityError(
f"candidate talk {assessment.talk_filename!r} appears twice"
)
seen.add(assessment.talk_filename)
def result(
verdict: str, selected: str | None, *reasons: str
) -> TalkIdentityAssessment:
codes = list(reasons)
# A master, backup, or static export never carries a bare `matched`
# verdict into persistence: the owner records which artifact is the
# published source before its contents become a talk's evidence.
if artifact_role != ROLE_DELIVERY and verdict == VERDICT_MATCHED:
verdict = VERDICT_REVIEW_REQUIRED
codes.append(REASON_NON_DELIVERY_ARTIFACT)
elif artifact_role != ROLE_DELIVERY:
codes.append(REASON_NON_DELIVERY_ARTIFACT)
return TalkIdentityAssessment(
pptx_path=facts.pptx_path,
verdict=verdict,
artifact_role=artifact_role,
selected_talk_filename=selected if verdict == VERDICT_MATCHED else None,
reason_codes=tuple(dict.fromkeys(codes)),
source_identity=source_identity,
candidates=assessments,
)
if not assessments:
return result(VERDICT_UNMATCHED, None, REASON_NO_CANDIDATE_TALKS)
selectable = [item for item in assessments if item.selectable]
if len(selectable) == 1:
return result(VERDICT_MATCHED, selectable[0].talk_filename, REASON_MATCHED)
if len(selectable) > 1:
return result(VERDICT_REVIEW_REQUIRED, None, REASON_AMBIGUOUS_CANDIDATES)
contradicted = [item for item in assessments if item.agreeing and item.conflicting]
if contradicted:
return result(VERDICT_REVIEW_REQUIRED, None, REASON_CONFLICTING_SIGNALS)
filename_only = [
item
for item in assessments
if item.signals[SIGNAL_FILENAME_SIMILARITY] == SIGNAL_AGREE
and not item.conflicting
]
if filename_only:
return result(VERDICT_REVIEW_REQUIRED, None, REASON_FILENAME_SIMILARITY_ONLY)
return result(VERDICT_UNMATCHED, None, REASON_NO_AGREEING_SIGNAL)
def unassessed_legacy_binding(pptx_path: str) -> dict[str, Any]:
"""The assessment for a talk binding made before assessments existed.
Migration cannot prove a binding it did not witness, and inventing a
`matched` verdict for one would forge exactly the evidence this module was
written to require. It cannot call the binding wrong either — most legacy
bindings are right. `review_required` is the only honest verdict: the record
upgrades, the binding survives, and nothing downstream may treat it as
proven until someone looks.
"""
return {
"schema_version": PPTX_TALK_IDENTITY_SCHEMA_VERSION,
"pptx_path": pptx_path,
"verdict": VERDICT_REVIEW_REQUIRED,
"artifact_role": ROLE_DELIVERY,
"selected_talk_filename": None,
"reason_codes": [REASON_UNASSESSED_LEGACY_BINDING],
# Null rather than absent, for the same reason the candidates list is
# empty rather than absent: migration read no bytes, and saying so is a
# different statement from the field never having existed.
"source_identity": None,
# Empty rather than absent: migration assessed no candidates, which is
# a different statement from having assessed some and reported none.
"candidates": [],
}
_SOURCE_IDENTITY_FIELDS = ("algorithm", "digest", "size_bytes")
# Mirrors `tracking_database`'s PPTX source-fingerprint contract, restated
# rather than imported because that module imports THIS one
# (`unassessed_legacy_binding`), so reaching back would cycle.
# `tests/test_pptx_talk_identity.py` pins the two to each other, so a contract
# change landing in one file and not the other fails CI instead of leaving the
# assessment accepting generations the database would refuse.
_SOURCE_IDENTITY_ALGORITHMS = frozenset({"sha256"})
_SHA256_DIGEST_LENGTH = 64
_LOWER_HEX = frozenset("0123456789abcdef")
def _source_identity_comparable(value: object) -> TypeGuard[Mapping[str, Any]]:
"""Whether a source identity is a valid generation, not merely present.
Held to the same contract the extractor's fingerprint is held to, because
the two are compared to each other. A looser reading here would accept a
generation the database would refuse — `{"algorithm": "x", "digest": "x",
"size_bytes": 0}` is not a deck anything could have read — and an
assessment carrying one would claim a binding proven against bytes that
cannot exist.
A partial identity is not a weak match, it is an unusable one: comparing on
whichever fields happen to be present would let a record missing `digest`
agree with anything that shares its size.
"""
if not isinstance(value, Mapping):
return False
if set(value) != set(_SOURCE_IDENTITY_FIELDS):
return False
if value["algorithm"] not in _SOURCE_IDENTITY_ALGORITHMS:
return False
digest = value["digest"]
if (
not isinstance(digest, str)
or len(digest) != _SHA256_DIGEST_LENGTH
or not set(digest) <= _LOWER_HEX
):
return False
size = value["size_bytes"]
# A zero-byte deck is not a deck. `bool` is an `int` in Python, so it is
# excluded before the range check rather than sliding through as 0 or 1.
return not isinstance(size, bool) and isinstance(size, int) and size >= 1
def _same_source_generation(
stored: Mapping[str, Any], observed: Mapping[str, Any]
) -> bool:
"""Exact agreement on every field, never a subset.
The algorithm is compared too: the same digest string under two algorithms
is a coincidence of encoding, not the same bytes.
"""
return all(stored[field] == observed[field] for field in _SOURCE_IDENTITY_FIELDS)
def binding_refusal(
assessment: object,
*,
pptx_path: str,
talk_filename: str,
observed_source_identity: Mapping[str, Any] | None,
) -> str | None:
"""Say why an assessment fails to authorize a binding, or None if it does.
One predicate, two callers. The owner writer raises on it so an unproven
binding is never persisted; preflight reports it so a binding persisted
before this contract existed cannot pass as proven. Two copies of this rule
would drift, and the direction they drift is a reader trusting what a writer
would have refused (`stateful-artifacts` -> Hints, Not Authority).
Checks the whole triple, not the verdict alone: an assessment names a deck
AND a talk, so one that proves a different pair proves nothing about this
row. Reason codes are checked because every code but the matched one
explains a refusal.
Two separate things are checked about the deck generation, and they are not
the same requirement:
* The assessment must NAME the generation it read. Always. A path is not a
deck: v1 pinned an assessment to `pptx_path` alone, so replacing the file
at that path kept the `matched` verdict and handed the new deck's contents
to the talk under a proof about different bytes.
* It must AGREE with an independent observation, when the caller has one.
`observed_source_identity` is REQUIRED, never defaulted, so a caller states
which case it is in rather than falling into one. `None` says "I have no
independent observation" — true of `mutate-tracking-database.py`, which
takes a database and a plan and never touches the vault. That is not a pass:
the assessment must still carry a comparable generation, so every v1
assessment and every unwitnessed migration stamp still refuses. It is
`preflight-vault.py` that observes the deck and makes the comparison real.
A caller holding an observation must not pass `None` to skip the
comparison — that is the fail-open shape the observation gate was made
required to avoid. Preflight treats an unobservable deck as its own finding
rather than as an absent observation.
"""
if not isinstance(assessment, Mapping):
return "identity_assessment_missing"
missing = {
"schema_version",
"pptx_path",
"verdict",
"artifact_role",
"selected_talk_filename",
"reason_codes",
"source_identity",
"candidates",
} - set(assessment)
if missing:
return "identity_assessment_incomplete"
if assessment["schema_version"] != PPTX_TALK_IDENTITY_SCHEMA_VERSION:
return "identity_assessment_schema_unsupported"
if assessment["verdict"] != VERDICT_MATCHED:
return "identity_verdict_not_matched"
if assessment["pptx_path"] != pptx_path:
return "identity_deck_mismatch"
if assessment["selected_talk_filename"] != talk_filename:
return "identity_talk_mismatch"
if assessment["artifact_role"] != ROLE_DELIVERY:
return "identity_non_delivery_artifact"
codes = assessment["reason_codes"]
if not isinstance(codes, list) or not all(isinstance(code, str) for code in codes):
return "identity_reason_codes_invalid"
if sorted(set(codes)) != sorted(MATCHED_REASON_CODES):
return "identity_reason_codes_contradict_verdict"
table_refusal = _candidate_table_refusal(assessment["candidates"], talk_filename)
if table_refusal is not None:
return table_refusal
# Last, deliberately. Everything above asks whether the assessment is a
# coherent proof at all; this asks whether it is a proof about the bytes
# that are there now. Running it earlier would mask a malformed assessment
# behind a generation complaint and change which defect the operator sees
# first.
stored_identity = assessment["source_identity"]
if not _source_identity_comparable(stored_identity):
return REASON_SOURCE_UNOBSERVABLE
if observed_source_identity is not None and not _same_source_generation(
stored_identity, observed_source_identity
):
return REASON_GENERATION_STALE
return None
def _candidate_table_refusal(candidates: object, talk_filename: str) -> str | None:
"""Check the evidence behind the verdict, not just the verdict.
A `matched` verdict over an empty candidate table is a conclusion with
nothing under it — which is exactly what a fabricated assessment looks like.
The table must show this talk winning the way `assess_pptx_talk_identity`
makes it win: corroborated by a selecting signal, contradicted by none, and
with no rival equally corroborated.
"""
if not isinstance(candidates, list) or not candidates:
return "identity_candidate_table_missing"
selected: tuple[tuple[str, ...], tuple[str, ...]] | None = None
rivals = 0
for candidate in candidates:
if not isinstance(candidate, Mapping):
return "identity_candidate_table_invalid"
name = candidate.get("talk_filename")
signals = candidate.get("signals")
stored_agreeing = candidate.get("agreeing")
stored_conflicting = candidate.get("conflicting")
if (
not isinstance(name, str)
or not isinstance(signals, Mapping)
or not isinstance(stored_agreeing, list)
or not isinstance(stored_conflicting, list)
):
return "identity_candidate_table_invalid"
# The signal map is the evidence; the two arrays are its summary. Read
# the evidence and recompute the summary, so a candidate cannot assert a
# standing its own readings do not support.
if set(signals) != set(SIGNAL_NAMES) or any(
signals[key] not in SIGNAL_VERDICTS for key in signals
):
return "identity_candidate_signals_invalid"
agreeing, conflicting = derive_candidate_standing(signals)
if list(agreeing) != stored_agreeing or list(conflicting) != stored_conflicting:
return "identity_candidate_standing_contradicts_signals"
if name == talk_filename:
if selected is not None:
return "identity_candidate_table_invalid"
selected = (agreeing, conflicting)
elif agreeing and not conflicting:
rivals += 1
if selected is None:
return "identity_candidate_absent"
selected_agreeing, selected_conflicting = selected
if not selected_agreeing or selected_conflicting:
return "identity_candidate_not_selectable"
if rivals:
return "identity_candidate_not_unique"
return None.tessl-plugin
rules
skills
illustrations
presentation-creator
references
patterns
build
deliver
prepare
scripts
shownotes-publisher
vault-clarification
vault-ingress
references
scripts
vault-profile