Files
promptkit/docs/roadmap/audit/catalog.md

35 KiB

Consolidated Pre-1.0 Audit Catalog

Consolidated on 2026-11-04 from the 11 audit documents in this directory. Their 41 numbered findings are represented by 34 entries below. Entries that describe the same underlying issue share one remediation scope; missing regression coverage for an identified defect is included with that defect. Some broad testing findings consequently support more than one entry.

The order reflects consequence, exposure, and the value of clarifying public contracts before v1.0. Confirmed defects and conditional security exposure come first, followed by contract/test gaps, resource efficiency, and maintainability. This ordering does not upgrade the original severities or turn every cleanup into a release gate. The source audits retain their evidence, qualifications, and validation results. None of these entries is marked remediated by this documentation-only consolidation.

1. Update The Audited Maintainer Toolchain For Applicable Security Fixes

Conditional security exposure. The audited Go 1.27.0 toolchain predates networking fixes applicable to HTTP clients, including HTTP/2 CPU exhaustion and conditional certificate-trust exposure. Use a patched maintainer toolchain and repeat the focused security assessment against it. Actual downstream exposure depends on the toolchain that builds the consumer and its transport and trust configuration; raising PromptKit's minimum Go requirement is a separate compatibility decision, not an implied remedy.

Sources: Security 1.

2. Bound Authentication-Probe Response Consumption

Confirmed resource/security defect. Authentication diagnostics read a successful upstream body with unbounded io.ReadAll. A deadline does not bound the bytes a fast server can supply. Decision 3 selects a fixed 1 MiB internal constant and explicit overflow diagnostics, with credential acceptance unknown. Implementation remains pending. Overflow should not be interpreted as proof of rejected authentication. Relocating the provider adapter in entry 26 would not itself fix this defect.

Sources: Resources 1, Security 2.

3. Avoid Exponential Expansion During Convenience Source Conversion

Confirmed resource defect. ProfileSource and BackendSource conversion expand repeated references before ConfigKit performs its bounded snapshot. A small shared acyclic graph can therefore cause exponential work and allocation. Preserve shared references during conversion, with suitable cycle and slice-view handling, rather than duplicating ConfigKit's validation or introducing PromptKit-side raw-source limits. Add focused shared-graph and deferred-failure regressions for both convenience helpers.

Sources: Resources 2, Testing 3.

4. Resolve The ArtifactReader Buffer-Ownership Contract

Confirmed race under the documented collaborator contract. The public reader contract permits buffer reuse after Read returns, before PromptKit can finish copying it. Concurrent preparation with a compliant custom reader can race. Decision 1 selects ownership transfer on successful return; implementation remains pending. Align adapters, GoDoc, and concurrency tests with that rule. An immediate copy alone cannot guarantee safety under the old immediate-reuse permission. No default-reader defect was established.

Sources: Interfaces 1.

5. Preserve Exact Numbers In Programmatic Provider Sources

Confirmed data-integrity defect. Convenience source conversion falls back from integer parsing to float64 without checking precision, silently changing some accepted json.Number values. Preserve an exact ConfigKit-compatible representation, or defer an unsupported-value error to ConfigKit instead of rounding or converting the number into a string. Regression coverage should include exact-number boundaries, nested typed collections, mutation isolation, and deferred unsupported/cyclic-value errors for both source helpers.

Sources: Correctness 1, Testing 3.

6. Make Provider-Native Schema Constraints Self-Contained

Confirmed implementation gap; self-contained schemas selected. Local validation freezes referenced schema resources, but the provider receives only the root document and cannot resolve its local external references. Decision 2 selects self-contained schema documents and removal of external-resource loading. Reject references requiring another document during preparation with an actionable error; retain references within the selected document. Add coverage for early rejection and for self-contained schemas reaching the provider intact. Implementation remains pending. Entry 21 is a separate compilation refactor; coordinate it with this simplification rather than preserving unnecessary external-resource machinery.

Sources: Correctness 2, Testing 5.

7. Preserve The Owning Operation's Public Error Category

Confirmed classification defect. Public error conversion searches nested causes in a global priority order, allowing a collaborator's sentinel to hide the enclosing operation's category. Map the owning boundary independently while retaining the original cause for errors.Is/errors.As. Add composed cause regressions; simply reordering global checks can break legitimate direct not-found versus load-failure distinctions. Carry explicit owning-operation information through translation. Retaining nested causes may legitimately make multiple public categories match through errors.Is; the remedy preserves the owning category rather than requiring category exclusivity.

Sources: Error handling 1, Testing 4.

8. Distinguish Response Stream Failures From Malformed JSON

Confirmed error-handling defect. Non-context I/O failures while decoding a successful HTTP response or checking its end are reported as malformed JSON, losing the transport cause; complete JSON followed by a read failure can also be misreported as trailing data. Retain and classify reader failures separately using the existing redacted transport boundary. Preserve cancellation precedence and genuine malformed/truncated/oversized-content handling. Cover both read locations without adding transport retries.

Sources: Error handling 2, Testing 4.

9. Return Invalid Diagnostic Request Construction As A Go Error

Confirmed diagnostic-contract defect. Some invalid inference settings fail before dispatch yet produce a completed report with a nil Go error. Propagate local request-construction failures through ErrInvalidRequest and add a no-dispatch regression. Preserve intentionally completed diagnostic outcomes for missing credentials, capacity outcomes, and unsupported or inapplicable operations; not every no-dispatch outcome is invalid configuration. Use explicit preparation-stage failure information rather than inferring the stage from a sentinel alone or from an empty attempt list.

Sources: Error handling 3, Testing 4.

10. Remove Quadratic Requirement-Evidence Union Work

Confirmed algorithmic inefficiency. A left-heavy recognized condition can repeatedly copy growing missing-key evidence sets, producing quadratic work. Use operation-local accumulation or ownership-aware merging while preserving classification and conservative inspection coverage. Do not address this by adding expression limits or expanding the recognized template language. Entry 23's traversal cleanup is related but is not a substitute for fixing this specific accumulation algorithm.

Sources: Efficiency 1.

11. Exercise RunRequest's Privacy Formatting Boundary

Missing protection, not a demonstrated leak. Request formatting methods have no execution coverage despite owning a privacy-sensitive public boundary. Add focused tests with distinct synthetic private markers for the relevant value/pointer formatting paths and JSON omission behavior. Assert privacy and the documented boundary, not an incidental complete diagnostic or JSON shape.

Sources: Testing 1.

12. Correct Profile Inspection Credential Documentation

Public-contract documentation defect. Inspection GoDoc incorrectly makes required credentials and an environment variable mutually exclusive. Actual behavior permits an explicit profile environment variable while suppressing only the backend-derived default when required credentials are selected. Correct the field/method GoDoc and consumer example, keeping the established configuration behavior and DTO shape.

Sources: Interfaces 2.

13. Correct The Configured Provider-Map Wire Documentation

Integration-contract documentation defect. The wire document says backend and profile provider maps replace one another, but configuration recursively overlays them; runtime replacement is a separate rule. Align the integration summary with the canonical format reference rather than maintaining a second conflicting precedence definition. Entry 19 concerns the efficiency of the existing overlay, not a change to its semantics.

Sources: Interfaces 3.

14. Remove Stale Identity And Version GoDoc

Public-contract documentation defect. Inspection comments still describe trimmed profile IDs, and listing comments describe a removed prompt-version field. Update them to the implemented literal identity and current collection version model. Do not normalize meaningful whitespace or reintroduce a field to match obsolete comments.

Sources: Interfaces 4.

15. Cover The Public Single-Schema-File Option

Public wiring coverage gap. Direct filesystem-validator tests do not exercise WithSchemaFile through engine construction. Add offline temporary file cases through public preparation/validation, including option precedence and relevant file errors. This is a supported feature, not dead code; entry 32 removes only an unused private helper result.

Sources: Testing 2.

16. Detach Inert Prepared Handles From The Execution Owner

Avoidable retention. Used or discarded prepared handles retain their runner, and therefore the engine's captured configuration and collaborators. Use a narrower ownership identity or clear the unnecessary owner reference safely. Preserve foreign-owner rejection, one-time claim, namespace-view behavior, and available details. This is unnecessary retention when a handle outlives its engine, not evidence of an ever-growing global leak.

Prefer a small standalone ownership token that preserves identity after use/discard without retaining the runner graph. Its distinct identity must not depend on zero-sized allocations comparing unequal. If clearing the owner pointer instead, synchronize the currently unlocked ownership check with that mutation and preserve ownership/state behavior under concurrent claim/discard.

Sources: Resources 3.

17. Bound Repair Feedback's Temporary Serialization

Avoidable peak allocation. Feedback formatting serializes potentially large diagnostic text before truncating the final message, so its existing output bound does not bound scratch memory. Produce bounded encoded feedback incrementally, preserving the existing output semantics and complete stored validation diagnostics and previous candidate. A new raw-diagnostic input limit is not implied.

Use representative allocation measurements for large and heavily escaped diagnostics to assess the remedy, alongside the existing output-behavior tests. Keep the encoder proportionate; the output bound does not establish an exact peak-heap guarantee or justify a general-purpose encoding framework.

Sources: Resources 4.

18. Detach Normalized Session IDs From Large Input Strings

Avoidable retention. A short trimmed session ID can retain the allocation of a much larger padded caller string. Clone the accepted normalized value at its ownership boundary. Preserve trimming, accepted content, code-point validation, and resulting wire/hash content rather than adding a raw-input size restriction.

Sources: Resources 5.

19. Avoid Repeated Descendant Cloning During Provider Overlay

Construction-time inefficiency. Recursive overlays repeatedly clone and sort overlapping descendant maps, giving work proportional to tree size times depth. Existing depth bounds mean this is not unbounded quadratic growth. Clone ownership once or use a single traversal while retaining recursive-map, null, and array semantics. Coordinate with entry 24 without assuming all JSON walkers have interchangeable policies.

Compare representative nested overlays before and after the change for allocation/work reduction. Balance the measured benefit against implementation complexity, preserving input isolation instead of removing necessary copies.

Sources: Efficiency 2.

20. Index Filtered Listings By Namespace

Repeated inspection overhead. Filtered listing currently copies and scans the complete inventory even when few or no entries match. Capture namespace buckets or equivalent ranges so queries operate on the relevant subset. Preserve ordering, exact identity matching, cancellation, and caller-owned results. A pagination API or runtime cache is not needed for this improvement.

Evaluate representative namespace counts and match sizes, including absent namespaces, and account for additional construction cost and retained indexing memory. Choose buckets or ranges based on that tradeoff. These measurements and those for entries 17 and 19 inform the changes; they add no performance contract or recurring release gate.

Sources: Efficiency 3.

21. Share Schema Compilation And Declare The Runner's Real Dependency

Maintainability and interface clarity. Four host-file/fs.FS, direct/prepared paths repeat the schema compilation lifecycle. The runner also declares a validator interface while requiring preparation through a runtime assertion. Share the lifecycle behind source-specific adapters and make that dependency explicit. Preserve malformed-output short-circuiting before schema I/O, source containment, exact numbers, cancellation, and frozen plans. Retain independent cross-source tests; do not force whole entry points to be identical.

Sources: Complexity 1, Equivalence 1.

22. Decompose Configuration Validation And Materialization

Maintainability. Large configuration operations mix record-specific validation, resource capture, and effective-profile construction. Extract focused helpers with visible inputs and ownership, rather than another generic validation framework. Preserve final-handoff validation, presence/null rules, origins, and meaningful fail-fast/error-precedence behavior. Do not turn incidental ordering of independent validation failures into a new guarantee. The configuration-boundary ADR remains authoritative; this is not a proposal to inspect raw ConfigKit sources.

Sources: Complexity 2.

23. Clarify Requirement Traversal And Share Branch Orchestration

Maintainability. Separate recognition/evaluation from reachability and evidence bookkeeping, particularly the repeated if/with branch protocol. Keep their scope differences explicit and retain independent comparisons with the actual Go renderer. Preserve conservative partial coverage and inactive computed-name behavior. This does not justify a general template interpreter or stronger execution-readiness promises from requirements inspection.

Sources: Complexity 3, Equivalence 3.

24. Centralize Compatible JSON Copying Without Conflating Policies

Maintainability and ownership clarity. The facade maintains a separate reflection traversal for already-normalized values despite an existing internal/jsonvalue owner. Consolidate genuinely compatible structural copying while retaining DTO projection at the facade and distinct source encoding/runtime validation policies. Preserve concrete types, nils, exact numbers, schema keys, and ownership. Infallible projection must not acquire new errors, panics, or silent zero-value fallbacks. Entries 3 and 5 remain separate source-conversion defects, not reasons to reject pre-handoff sources.

Retain separate small traversals where ownership or validation policies differ enough that sharing would require a configurable reflection framework. Reducing duplicate code is useful only when it also simplifies the supported behavior.

Sources: Complexity 4, Equivalence 2.

25. Separate Attempt Accounting From Generation Control Flow

Maintainability. Generation coordination interleaves dispatch/retry policy with parallel return values and repeated evidence/observation projection. Introduce a small attempt result and focused accounting helpers. Preserve built-in versus injected-client differences, permit release before callbacks or backoff, frozen requests, existing retry classification, private evidence, and known/unknown usage distinctions. Do not collapse legitimately different dispatch strategies merely to reduce lines.

Sources: Complexity 5.

26. Move OpenRouter Authentication Protocol Details Into Its Adapter

Architectural ownership. Use-case code currently interprets OpenRouter's account-response fields and provider-relative endpoint while the outbound adapter owns HTTP execution. Place protocol construction/recognition with the outbound integration; keep diagnostic selection, applicability, cancellation, completion, and neutral reporting in the use case. Preserve credential/body privacy and anonymous probing. No plugin framework, reverse dependency, or blanket prohibition on HTTP facts is needed. Coordinate the body-bound fix in entry 2, which is a distinct behavioral change.

Sources: Boundaries 2.

27. Narrow Smoke-Value Copy Helpers To Real Consumers

Ownership cleanup. A request cloner has only its self-test as a caller; the full-report cloner is used to detach only a target. Express that actual copy operation directly and retire unused broader cloning after checking callers. Keep facade request/report projection, active backend cloning, provider-map errors, ownership tests, and redaction. Do not introduce shared public/internal DTOs or an additional full-report copy.

Sources: Boundaries 3.

28. Give Bundled Catalog Expectations One Test Owner

Test duplication. Complete bundled profile/model/provider expectations are repeated across several test layers. Keep one independently specified asset oracle, with smaller tests for distinct loading, wire, and diagnostic behavior. Use controlled fixtures where bundled churn is irrelevant and structural assertions rather than formatted-map strings. Retain meaningful bundled coverage instead of deriving every expected value from the loader under test.

Sources: Testing 7.

29. Stop Pinning The Opaque Artifact Hash Algorithm In Tests

Over-specified tests. Artifact tests and a benchmark assert a literal hash algorithm despite the public value being opaque. Assert the documented equality/ownership relationships and actual byte/size behavior instead; keep benchmark setup outside its timed work. Coordinate with entry 31, but do not turn today's hash representation into a new compatibility guarantee.

Sources: Testing 6.

30. Remove Unconsumed Backend Presence Bookkeeping

Low-priority state cleanup. Backend field-state maps and QueueCapacitySet have no runtime reader; effective values and ConfigKit already own queue defaulting and provenance. Remove only these unused records and adjust tests to assert effective behavior or operator inspection. Keep profile/input presence tracking, explicit zero capacity, and derived defaults.

Sources: Dead code 1.

31. Retire Duplicate Fields In Captured Prompt Definitions

Low-priority representation cleanup. Captured definitions duplicate the output format and carry an unused runtime message-file field after content materialization. Use the captured output contract and text as their respective sources of truth. Preserve real YAML content_file loading, origins, and the request-override default rule. Removing serialized internal fields changes current definition hashes: retain documented opaque equality relationships, not an invented bit-identical encoding promise. Record the observable hash change in release notes so consumers can account for invalidated comparisons or caches, without establishing a permanent hash algorithm or encoding contract.

Sources: Dead code 2.

32. Remove Unused Private Diagnostic State And Helper Results

Low-priority cleanup. A private reachability outcome echoes an endpoint that report assembly never reads; the schema-file helper returns a directory that its only caller discards. Remove the unused state/result while preserving actual sanitized request/report evidence, directory calculation, file checks, and public single-file schema support. Keep privacy tests against the values that real execution consumes.

Sources: Dead code 3.

33. Remove Orphan Internal Helpers And Their Self-Tests

Low-priority cleanup. filecatalog.RelativePath and resourceNamespaceFromID have only their own tests as callers, and the runner test's stringPtr helper is entirely unused. Remove those narrow surfaces without replacement, preserving real discovery, identity qualification, and namespace inventory/filtering coverage. Reachability from examples alone is not a reason to remove optional public APIs.

Sources: Dead code 4.

34. Decide Whether To Retain The Legacy Capacity Client Wrapper

Decision-dependent architectural cleanup. The old capacity client wrapper is used by tests, whereas production dispatch uses the generation coordinator. It is also explicitly retained in current internal documentation; the dead-code audit does not classify it as obsolete functionality. If that retention decision is revised, exercise the production coordinator in runner tests and move any needed one-shot capacity scaffolding into tests before retiring the wrapper. Preserve FIFO, cancellation, independent-pool, and panic-release coverage. This is not a second scheduling algorithm or a confirmed concurrency defect.

Sources: Boundaries 1, Dead-code retention qualification.

Resolved Decisions

Decision 1: ArtifactReader Result Ownership And Lifetime

Related finding: 4.

Status: Accepted; implementation pending.

Decision: A successful Read transfers the returned artifact and its mutable body storage to PromptKit. The reader must stop mutating the returned artifact and body, including through retained aliases. Fresh independent results are the simplest implementation. A reader may reuse private working buffers if it copies into independent result storage before returning.

Keep the existing interface signature and defensive adapter copy initially. Removing redundant copies is a separate optimization, not part of this contract correction. No borrowing lifetime or acknowledgement/release API is introduced.

Rationale: The reader controls storage until return and can therefore make that handoff safe. Copying only after return cannot make the current permission to immediately reuse storage safe; a reader-local mutex also cannot protect the caller's later copy.

Alternatives considered: Borrowing until the enclosing operation returns makes the lifetime difficult for a reader to observe and requires coordination across concurrent calls. An explicit release protocol enables pooling but adds lifecycle machinery. Caller-provided buffers or streaming would require a broader interface redesign. None is needed for this correction.

Remediation follow-through: Update GoDoc, adapter assumptions, and concurrency regressions together. Explain the migration for readers that reuse returned storage in release notes as a deliberate pre-1.0 contract correction. This record does not itself implement the change.

Decision 2: Provider Submission Of Multi-Resource Schemas

Related findings: 6 and 21.

Status: Accepted; implementation pending.

Decision: Require self-contained schema documents. Continue loading the selected schema from a file and supporting references within that document, such as #/$defs/address. Reject references requiring another document during preparation with an actionable error. Remove external-resource loading support and update the owning documentation and tests as a deliberate compatibility change. Do not introduce a local-only validation mode or implement bundling in this remediation.

Rationale: OpenRouter's documented structured-output request accepts one schema object, with no accompanying collection of external schema files. PromptKit currently supports local validation of resources it cannot faithfully submit. Requiring a self-contained document resolves that mismatch without adding a schema transformation subsystem. Provider-specific schema restrictions still apply; self-containment does not guarantee universal provider acceptance.

Alternatives considered: Bundling could preserve multi-file authoring and reuse, but its value does not currently justify the machinery needed to preserve reference semantics. Retain a schema bundler as a possible future enhancement, not approved implementation work. An explicit local-only mode would preserve external local validation but add a distinct execution behavior that is not needed for the selected scope.

Remediation follow-through: Cover external-reference rejection and retained in-document references, including recursion where otherwise supported. Update schema documentation and release notes, and simplify the shared compilation work in finding 21 accordingly. This record does not itself implement the change.

Decision 3: Authentication Response Budget And Overflow Outcome

Related findings: 2 and 26.

Status: Accepted; implementation pending.

Decision: Bound the authentication protocol's response body to 1 MiB (1,048,576 bytes), defined as a named internal constant. This is a generous practical processing allowance, not an upstream protocol limit. Do not add a public configuration option now; keep the value centralized so a future option can be introduced if needed. This limit does not apply to inference responses or establish an application deadline.

Enforce the budget against bytes actually read, regardless of declared content length. Detect overflow, stop reading, and close without unbounded draining. Report an explicit response-limit diagnostic with credential acceptance unknown, retaining independently collected HTTP status and timing information. Overflow is neither evidence of rejected credentials nor proof of malformed JSON. The consuming application decides what to do with the diagnostic.

Alternative considered: A caller-configurable budget with a finite default would accommodate unusual deployments, but adds public configuration without a current demonstrated need. Reconsider if such a need arises.

Remediation follow-through: Add focused boundary and overflow coverage, including missing or inaccurate content lengths. Represent overflow explicitly in the diagnostic report and update its owning documentation. Keep this fix independent of adapter relocation so architectural cleanup does not delay the resource remedy. This record does not itself implement the change.

Open Decisions

Work through the remaining decisions below in order, retaining their original numbers. These are unresolved choices, not additional findings or approved changes to public contracts. A decision blocks its dependent remediation, not unrelated fixes. In particular, updating the maintainer toolchain need not wait for the consumer-minimum decision. Implementation details and optional cleanup do not become release gates merely by appearing in this catalog.

Decision 4: Exact Numbers And The Source-Conversion Boundary

Related findings: 3, 5, and 24.

Question: Which exact numeric values can the convenience helpers preserve through the current ConfigKit mapping boundary, and what happens to others?

Recommendation: Preserve supported values through the complete conversion, load, and outbound-encoding path; defer an unsupported-value error when exact preservation is unavailable. Compare numeric meaning rather than spelling or successful parsing alone. Address shared-graph expansion in the same adapter with completed-conversion memoization, distinct cycle tracking, and correct slice-view identity, preserving source capture and deferred failures.

Alternative: Request upstream support for additional exact numeric/value forms, then simplify or remove the relevant PromptKit conversion. This may provide a cleaner long-term boundary and broader preservation, but introduces an upstream dependency and should not postpone fixing silent rounding or exponential expansion. Runtime JSON copying remains a separate policy.

Resolve before implementation: Establish the supported numeric round-trip cases and whether broader upstream support is needed now. Do not substitute numeric-looking strings or introduce a second raw-source validation system.

Decision 5: Consumer Go Minimum After The Toolchain Update

Related finding: 1.

Question: Should the security fixes also change PromptKit's declared minimum consumer Go version?

Recommendation: Update the maintainer toolchain and repeat the focused assessment promptly; initially keep the consumer minimum decision separate. Advise affected consumers to rebuild with a patched toolchain. This recognizes that PromptKit publishes source and that downstream build/transport choices control the deployed exposure.

Alternative: Raise the declared minimum to the selected patched release. This makes the supported floor clearer and steers module consumers toward the fixed toolchain, but changes compatibility and does not repair already-built applications. Assess it under the existing release policy rather than treating it as an automatic consequence of the scanner output.

Resolve before changing the minimum: Confirm current advisory applicability, select the patched version, and decide whether changing the supported consumer floor is justified. No new recurring release gate is implied.

Decision 6: Retention Of The Legacy Capacity Client Wrapper

Related finding: 34.

Question: Does the wrapper still justify a production surface for its currently documented test-focused purpose?

Recommendation: Retire the production wrapper after moving the runner's integration test to the production generation coordinator. Keep direct manager coverage and any useful one-shot scaffolding in tests. This reduces maintenance and makes assembled scheduling tests reflect production while preserving the actual FIFO, cancellation, independent-pool, and panic-release scenarios.

Alternative: Retain it if a concrete internal use justifies the small adapter. This avoids test migration and preserves that convenient composition, but keeps a second assembly surface to understand and maintain. Existing self-tests alone do not establish a future production need.

Resolve before removal: Confirm the intended retention decision and test ownership. This cleanup can be deferred without blocking the behavioral fixes; it is not evidence of a second scheduler or a concurrency defect.