PromptRunner.PacketLint (PromptRunnerSDK v0.9.0)

Copy Markdown View Source

Static authoring hazards in a packet.

packet doctor reports authoring gaps — a packet with no prompts, a prompt with no targets. packet lint reports authoring hazards: constructs that load, run, and produce a wrong answer without ever raising. Every check below corresponds to an observed way a packet silently misbehaves.

Errors

Findings that make the packet mean something other than what it says. Each one exits non-zero.

  • prompt_id_filename_mismatch — prompts are ordered by the numeric filename prefix, the sort key built by PromptRunner.Source.DirectorySource, not by id:. A mismatch reorders the run while the front matter still reads correctly.
  • prompt_filename_without_prefix — with no numeric prefix the file sorts last, by basename, among all other unprefixed files.
  • duplicate_prompt_id — two prompts claiming one id collide in progress state, runtime state, and run <packet> <id> selection.
  • unknown_target_repo — a target that names no manifest repo contributes no working directory and no verifier scope.
  • unknown_verify_repo — a verify entry scoped to a repo that does not exist resolves against nothing.
  • repo_group_in_targets@group syntax is a legacy-config feature. PromptRunner.RepoTargets is never consulted with packet repo groups, so the target expands to nothing.
  • unknown_verify_clause — an unrecognized key under verify: is parsed, stored, and never evaluated, so the contract is weaker than it reads.

Warnings

Findings that are usually wrong but legitimately intentional sometimes. They exit zero unless strict: true promotes them.

  • verify_command_without_timeout — the verifier runs commands with System.cmd("bash", ["-lc", command]) and no timeout, so a hung command hangs the whole run after the model work is already spent.
  • prompt_without_verify — completion falls back to the provider's own claim of success.
  • contract_without_commands — the contract has neither a commands: entry nor any content assertion (contains, matches, doc), so it is satisfied by an empty file.
  • changed_paths_only_vacuouschanged_paths_only reads git status --porcelain, so it can only see work that is still uncommitted. It passes vacuously in any packet where the session commits its own work.
  • inert_front_matter_keyreferences, required_reading, context_files, and depends_on are parsed and stored and then never read at runtime.

Timeout detection

A command counts as bounded when any of its segments — split on &&, ||, ;, and | — begins with a timeout token. Lint checks that timeout is invoked at all, not that every branch of a compound command is bounded; deciding the latter needs a shell parser.

Summary

Functions

Lints the packet rooted at root.

Types

finding()

@type finding() :: %{
  :kind => String.t(),
  :severity => String.t(),
  :message => String.t(),
  :prompt_id => String.t() | nil,
  :file => String.t() | nil,
  optional(:key) => String.t()
}

report()

@type report() :: %{
  packet: String.t(),
  root: String.t(),
  strict?: boolean(),
  findings: [finding()],
  errors: non_neg_integer(),
  warnings: non_neg_integer(),
  pass?: boolean()
}

Functions

lint(root, opts \\ [])

@spec lint(
  String.t(),
  keyword()
) :: {:ok, report()} | {:error, term()}

Lints the packet rooted at root.

Options:

  • :strict — promote every warning to an error.