CtrlK
BlogDocsLog inGet started
Tessl Logo

jbaruch/speaker-toolkit

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.

Quality

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

pptx_catalog_selection.pyskills/vault-ingress/scripts/

"""Live-observation selection for PPTX catalog visual evidence (#229).

A persisted receipt is a hint; what is on disk is the authority
(`stateful-artifacts` -> Hints, Not Authority). This module makes the two live
observations `classify_pptx_visual_evidence` requires — the deck's fingerprint
and the extraction artifact's digest — and returns one classified row per
catalog record.

One authority, two surfaces: `preflight-vault.py` turns these rows into
findings, and `classify-pptx-evidence.py` prints them as JSON for the ingress
workflow. Neither reimplements the observation or the classification.
"""

from __future__ import annotations

import hashlib
import os
import stat as stat_module
from pathlib import Path
from typing import Any, Mapping

from artifact_locator import (
    ArtifactLocatorError,
    classify_artifact_locator,
    materialize_artifact_locator,
)
from pptx_evidence import (
    PPTX_EXTRACTION_PIPELINE_VERSION,
    PPTX_EXTRACTION_SCHEMA_VERSION,
)
from tracking_database import (
    PPTX_VISUAL_EVIDENCE_DIAGNOSTICS,
    PPTX_VISUAL_EVIDENCE_FALLBACK,
    TrackingDatabaseError,
    classify_pptx_visual_evidence,
    pptx_visual_evidence_needs_extraction,
)

SELECTION_SCHEMA_VERSION = 1
_READ_CHUNK_BYTES = 1024 * 1024
# Containment depends on these primitives, so their absence is a refusal rather
# than a degraded mode: `getattr(os, "O_NOFOLLOW", 0)` would silently drop the
# no-follow guarantee and let a symlinked component escape the root.
_REQUIRED_OPEN_FLAGS = ("O_NOFOLLOW", "O_DIRECTORY")


def _open_contained(root: object, parts: tuple[str, ...]) -> int | None:
    """Open a descendant of ``root``, refusing every symlink below the root.

    Checking a resolved path and then opening it by name are two separate
    lookups; a symlink swapped in between them redirects the open outside the
    root. Each component is therefore opened relative to the previous
    descriptor with ``O_NOFOLLOW``, so the descriptor that gets hashed is the
    one that passed the check. The root itself is opened by name and may be a
    symlink: it is trusted configuration, exactly as the artifact-metadata
    contract documents.

    Returns None whenever the walk cannot be completed that way — a platform
    without descriptor-relative opens or without the no-follow primitives
    included. An uncertain answer must be the closed one, because this decides
    what gets read.
    """
    if not parts or os.open not in os.supports_dir_fd:
        return None
    if any(not hasattr(os, name) for name in _REQUIRED_OPEN_FLAGS):
        return None
    directory_flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | os.O_DIRECTORY
    no_follow = os.O_NOFOLLOW
    try:
        current = os.open(os.fspath(Path(str(root))), directory_flags)
    except (OSError, ValueError):
        return None
    try:
        for part in parts[:-1]:
            try:
                nested = os.open(part, directory_flags | no_follow, dir_fd=current)
            except OSError:
                return None
            os.close(current)
            current = nested
        try:
            descriptor = os.open(
                parts[-1],
                os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | no_follow,
                dir_fd=current,
            )
        except OSError:
            return None
    finally:
        os.close(current)
    if not stat_module.S_ISREG(os.fstat(descriptor).st_mode):
        os.close(descriptor)
        return None
    return descriptor


def digest_and_size(path: object, root: object) -> tuple[str, int] | None:
    """SHA-256 and byte count of one artifact, or None when it cannot be read.

    Catalog locators are root-relative by contract, and this enforces it
    without ever opening a path it has not walked: persisted state is a hint,
    never a licence to read an arbitrary host file. An absolute locator, a
    symlinked component below the root, a non-regular file, a platform without
    descriptor-relative opens, and an unreadable file all return None — the
    caller must not be able to mistake "not observed" for "matches".
    """
    if not isinstance(path, str) or not path.strip():
        return None
    if root is None:
        return None
    try:
        if classify_artifact_locator(path) != "relative":
            return None
        resolved = materialize_artifact_locator(path, root)
        parts = resolved.relative_to(Path(str(root))).parts
    except (ArtifactLocatorError, TypeError, ValueError):
        return None
    descriptor = _open_contained(root, parts)
    if descriptor is None:
        return None
    digest = hashlib.sha256()
    size = 0
    try:
        with os.fdopen(descriptor, "rb", closefd=True) as source:
            for chunk in iter(lambda: source.read(_READ_CHUNK_BYTES), b""):
                digest.update(chunk)
                size += len(chunk)
    except OSError:
        return None
    return digest.hexdigest(), size


def observed_source_fingerprint(
    pptx_path: object, pptx_source_dir: object
) -> dict[str, object] | None:
    """Fingerprint the deck as it exists now, in the extractor's shape."""
    observed = digest_and_size(pptx_path, pptx_source_dir)
    if observed is None:
        return None
    digest, size = observed
    return {"algorithm": "sha256", "digest": digest, "size_bytes": size}


def observed_artifact_digest(evidence: object, vault_root: object) -> str | None:
    """Digest the extraction artifact a receipt names, if it still exists.

    ``artifact.path`` is vault-root-relative. A deleted or replaced artifact
    must not stay authoritative.
    """
    if not isinstance(evidence, Mapping):
        return None
    artifact = evidence.get("artifact")
    if not isinstance(artifact, Mapping):
        return None
    observed = digest_and_size(artifact.get("path"), vault_root)
    return None if observed is None else observed[0]


def classify_catalog(
    database: Mapping[str, Any],
    *,
    vault_root: Path | str,
    pptx_source_dir: object,
) -> list[dict[str, Any]]:
    """Classify every catalog record against the live deck and artifact.

    A record whose receipt cannot be read is reported with a null
    classification and ``needs_extraction: true`` rather than dropped — a
    missing row would read as "nothing to regenerate".
    """
    catalog = database.get("pptx_catalog")
    if not isinstance(catalog, list):
        return []
    rows: list[dict[str, Any]] = []
    for index, record in enumerate(catalog):
        if not isinstance(record, Mapping):
            continue
        source = observed_source_fingerprint(record.get("pptx_path"), pptx_source_dir)
        artifact = observed_artifact_digest(record.get("visual_evidence"), vault_root)
        row: dict[str, Any] = {
            "index": index,
            "pptx_path": record.get("pptx_path"),
            "source_observed": source is not None,
            "artifact_observed": artifact is not None,
        }
        try:
            classification = classify_pptx_visual_evidence(
                record,
                extractor_schema_version=PPTX_EXTRACTION_SCHEMA_VERSION,
                pipeline_version=PPTX_EXTRACTION_PIPELINE_VERSION,
                observed_source_fingerprint=source,
                observed_artifact_digest=artifact,
            )
        except TrackingDatabaseError as exc:
            # Never surface the exception prose: a rejected receipt's message
            # names the value that came out of the database. Report the closed
            # code and its neutral wording instead (`no-secrets` -> Logging).
            reason_code = getattr(exc, "reason_code", "receipt_unreadable")
            row["classification"] = None
            row["needs_extraction"] = True
            row["reason_code"] = reason_code
            row["error"] = PPTX_VISUAL_EVIDENCE_DIAGNOSTICS.get(
                reason_code, PPTX_VISUAL_EVIDENCE_FALLBACK
            )
        else:
            row["classification"] = classification
            row["needs_extraction"] = pptx_visual_evidence_needs_extraction(
                classification
            )
        rows.append(row)
    return rows


__all__ = [
    "SELECTION_SCHEMA_VERSION",
    "classify_catalog",
    "digest_and_size",
    "observed_artifact_digest",
    "observed_source_fingerprint",
]

skills

README.md

tile.json