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

32 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. Introduce finite response consumption and clean closure, with an explicit choice of byte budget and overflow reporting. 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. Clarify ownership/lifetime per invocation and align adapters, GoDoc, and concurrency tests. This needs a deliberate public-contract decision before v1.0: an immediate copy alone cannot guarantee safety if the reader is allowed to mutate the buffer immediately. 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; packaging policy needs selection. Local validation freezes referenced schema resources, but the provider receives only the root document and cannot resolve its local external references. Select correct resource packaging, or an explicit local-only fallback policy, without naively inlining recursive schemas or silently dropping native constraints. Add a wire-level regression demonstrating a usable provider constraint, not merely successful local compilation. Entry 21 is a separate compilation refactor and does not solve this packaging problem.

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.

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.

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.

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.

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.

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.

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.

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.

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.

Open Decisions

Work through the decisions below in this order. 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 1: ArtifactReader Result Ownership And Lifetime

Related finding: 4.

Question: What ownership does a successful Read transfer, and when may an injected reader mutate or reuse the returned storage?

Recommendation: Transfer an independent result to PromptKit on successful return. The reader must stop mutating the returned artifact and its body, including through retained aliases. Fresh per-invocation storage is the simplest implementation; immutable shared data can remain shared if no collaborator mutates it. This removes the impossible immediate-reuse permission without adding synchronization or a release protocol to the interface. Explain the consumer impact as a deliberate pre-1.0 contract correction.

Alternative: Permit borrowing until the enclosing preparation/execution operation returns. This can support application-managed reuse, but a reader cannot generally observe that lifetime and concurrent calls need independent storage or caller coordination. If reuse immediately after Read returns is required, an explicit acknowledgement/release API is another viable design; it enables pooling at the cost of a larger interface and lifecycle change.

Resolve before implementation: Select the ownership/lifetime rule and update GoDoc, adapter assumptions, and the regression scenario together. Another unsynchronized copy is not a remedy for the current permission.

Decision 2: Provider Submission Of Multi-Resource Schemas

Related findings: 6 and 21.

Question: How should native structured output represent a schema whose local validation depends on external resources?

Recommendation: First investigate packaging the operation's captured resource graph into a self-contained provider constraint. Check identifiers, relative references, anchors, recursion, and supported dialects before choosing an encoding. Prefer correct packaging when it fits a proportionate scope, while keeping resource completeness distinct from any provider's supported schema subset. A standalone offline validation of the actual emitted constraint should establish the selected packaging behavior.

Alternative: Offer an explicit local-only validation choice when native submission cannot represent the resource graph. This preserves useful local validation and avoids building a general schema transformation system, but forgoes native generation constraints for that selected mode and needs a clear consumer-facing selection mechanism. Silently dropping native constraints is not equivalent to an explicit choice.

Resolve before implementation: Establish packaging feasibility and select the submission/fallback policy, including behavior for unsupported cases. Coordinate the compilation refactor with that result; it does not itself fix provider packaging or establish universal provider acceptance.

Decision 3: Authentication Response Budget And Overflow Outcome

Related findings: 2 and 26.

Question: What finite response budget should the authentication adapter apply, and how should a probe report exceeding it?

Recommendation: Select a conservative fixed budget for this small protocol, check actual streamed bytes regardless of declared length, and close on overflow without unbounded draining. Report the diagnostic failure with acceptance unknown, retaining any independently observed HTTP facts. Agree the exact byte count and its representation in the existing diagnostic report before coding; the catalog does not select either implicitly.

Alternative: Expose a caller-configurable budget with a finite default. This accommodates unusual legitimate responses but expands configuration and validation surface. It is worthwhile if a concrete consumer requirement cannot be served by an appropriately chosen fixed budget; it is not necessary merely to address the demonstrated unbounded read.

Resolve before implementation: Choose the size, overflow classification, and whether configurability is warranted. Keep this fix independent of adapter relocation so architectural cleanup does not delay the resource remedy.

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.