2026-10-26 12:41:36 +00:00
|
|
|
|
# Invocation reporting audit remediation
|
|
|
|
|
|
|
2026-10-26 14:33:31 +00:00
|
|
|
|
Status: remediation in progress; 5 of 7 findings complete.
|
2026-10-26 12:41:36 +00:00
|
|
|
|
|
|
|
|
|
|
## Review scope
|
|
|
|
|
|
|
|
|
|
|
|
Reviewed the reporting implementation from `2a1096b` through `7c035cc` against
|
|
|
|
|
|
the [feature roadmap](reporting.md), [implementation plan](implementation.md),
|
|
|
|
|
|
[ADR 0014](../adr/0014-invocation-reporting.md),
|
|
|
|
|
|
[ADR 0005](../adr/0005-invocation-outcomes.md), and the
|
|
|
|
|
|
[architecture policy](../policy/architecture.md).
|
|
|
|
|
|
|
|
|
|
|
|
The intended ownership is substantially implemented: core owns invocation
|
|
|
|
|
|
reporting, ordered presentation selection, coordinated delivery, and finalization;
|
|
|
|
|
|
the internal Cobra adapter supplies neutral parsing evidence; optional
|
|
|
|
|
|
integrations own native adaptation and command presentation. Providers remain
|
|
|
|
|
|
passive, and ckprompt depends on ckconfig without a reverse dependency.
|
|
|
|
|
|
|
|
|
|
|
|
The findings below concern missing presentation and error evidence within that
|
|
|
|
|
|
architecture. They do not require a different public architecture or automatic
|
|
|
|
|
|
rendering of application causes. No separate unrequested registration restriction,
|
|
|
|
|
|
concurrent-dispatch guarantee, or upstream-domain responsibility was identified.
|
|
|
|
|
|
|
|
|
|
|
|
Evidence includes source and test review, maintained example invocations, and
|
|
|
|
|
|
temporary public-API audit consumers outside the repository. The audit did not
|
|
|
|
|
|
modify implementation code or add tests, and did not rerun the full test suites.
|
|
|
|
|
|
|
2026-10-26 14:01:28 +00:00
|
|
|
|
The follow-up interaction audit at `1e532cd` reviewed reporting against existing
|
|
|
|
|
|
alias contexts, typed bindings, scope/input/state preparation, cancellation,
|
|
|
|
|
|
native reports, and maintained consumers. Representative successful invocations
|
|
|
|
|
|
covered command and scoped flag aliases with explicit zero and repeated values,
|
|
|
|
|
|
quiet help/version, aggregate configuration YAML, quiet comparison, concrete
|
|
|
|
|
|
request validation, and offline aggregate smoke testing. Findings 4 and 5 record
|
|
|
|
|
|
the additional gaps; findings 1–3 remain open and are not duplicated below.
|
|
|
|
|
|
|
2026-10-26 14:14:50 +00:00
|
|
|
|
The algorithmic audit at `ee76b0f` examined the reporting-specific parser passes,
|
|
|
|
|
|
delivery bookkeeping, deferred storage, native diagnostic partitioning, and
|
|
|
|
|
|
integration report coordination. It used source-level complexity analysis, not
|
|
|
|
|
|
benchmarks or real-world performance measurements. Selected algorithms were
|
|
|
|
|
|
excluded from reconsideration, including synchronous serialized reporting, FIFO
|
|
|
|
|
|
deferred delivery, rendering rich content under quiet mode, fresh backend trees,
|
|
|
|
|
|
and the chosen configuration/smoke report preparation boundaries. Findings 6 and
|
|
|
|
|
|
7 are implementation opportunities within those decisions.
|
|
|
|
|
|
|
|
|
|
|
|
No newly introduced quadratic-time algorithm was identified in the reviewed
|
|
|
|
|
|
paths. In particular:
|
|
|
|
|
|
|
|
|
|
|
|
- Reporting selection is linear in the number of flag occurrences. There are
|
|
|
|
|
|
four fixed reporting flags and at most two additional reverse searches for
|
|
|
|
|
|
selection provenance; these do not create a quadratic pass.
|
|
|
|
|
|
- Deferred insertion is amortized constant time plus callback-list copying;
|
|
|
|
|
|
draining is linear in queued messages and details, excluding callback/I/O
|
|
|
|
|
|
costs. The avoidable storage and handoff costs are described in finding 6.
|
|
|
|
|
|
- Native diagnostic snapshotting and partitioning are linear in source records,
|
|
|
|
|
|
diagnostic records, and the total related-location entries. Nested copying of
|
|
|
|
|
|
related locations is not quadratic in the actual input size.
|
|
|
|
|
|
- Explanation combination uses amortized slice appends. Configuration comparison
|
|
|
|
|
|
has two sides, and aggregate smoke execution has four selected operations;
|
|
|
|
|
|
neither introduces an unbounded nested traversal through all prior results.
|
|
|
|
|
|
|
|
|
|
|
|
The algorithmic audit found no additional ordinary correctness issue beyond
|
|
|
|
|
|
findings 1–5. It made no implementation changes and ran no tests or benchmarks.
|
|
|
|
|
|
|
2026-10-26 12:41:36 +00:00
|
|
|
|
## 1. Preserve native PromptKit operation failure explanations
|
|
|
|
|
|
|
2026-10-26 14:18:21 +00:00
|
|
|
|
Priority: P2. Status: complete.
|
|
|
|
|
|
|
|
|
|
|
|
- [x] Completed: bundled native operation failures now supply terminal explanations
|
|
|
|
|
|
without printing arbitrary application causes. Explicit provider context and
|
|
|
|
|
|
independent warnings retain their presentation paths. Native-error forwarding
|
|
|
|
|
|
and single-presentation regressions pass in ordinary and quiet modes.
|
|
|
|
|
|
Validation: `GOTOOLCHAIN=local go test ./...` in `integrations/ckprompt`.
|
2026-10-26 12:41:36 +00:00
|
|
|
|
|
|
|
|
|
|
### Finding and evidence
|
|
|
|
|
|
|
|
|
|
|
|
[WithRequestValidation and FromEngine](../../integrations/ckprompt/adapters.go)
|
|
|
|
|
|
carry native operation errors back to their callers, but their acquired terminal
|
|
|
|
|
|
explanations contain only configuration-loading diagnostic records.
|
|
|
|
|
|
[runRequestValidation](../../integrations/ckprompt/validation_command.go) and
|
|
|
|
|
|
[definitionFailure](../../integrations/ckprompt/command.go) then retain the native
|
|
|
|
|
|
error solely as `Cause` and present a generic operation heading when no acquired
|
|
|
|
|
|
explanation exists. Native request-validation and lookup failures consequently
|
|
|
|
|
|
lose their useful explanation at the CLI boundary.
|
|
|
|
|
|
|
|
|
|
|
|
Reproduced in the maintained composed example:
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
go run . promptkit requirements validate briefing --campaign spring
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Its entire diagnostic is:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
ERROR: Unable to validate the PromptKit request for prompt "briefing".
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
A separate public-API consumer using the bundled validation adapter confirmed
|
|
|
|
|
|
that the native error contains `missing required input artifact: topic`, while
|
|
|
|
|
|
the acquisition has neither an explanation heading nor a detail renderer. The
|
|
|
|
|
|
cause survives, but the operator cannot see the missing input. The maintained
|
|
|
|
|
|
`promptkit show prompt missing --campaign spring --quiet` invocation likewise
|
|
|
|
|
|
omits the native lookup explanation.
|
|
|
|
|
|
|
|
|
|
|
|
This falls short of useful access to native capabilities and the roadmap's
|
|
|
|
|
|
requirement to keep failures understandable. Separating causes from presentation
|
|
|
|
|
|
does not prohibit an integration from deliberately adapting native failure
|
|
|
|
|
|
content into an explanation. Existing native-failure tests primarily check
|
|
|
|
|
|
classification and cause identity while discarding the diagnostic destination,
|
|
|
|
|
|
so they do not protect this handoff.
|
|
|
|
|
|
|
|
|
|
|
|
### Required work
|
|
|
|
|
|
|
|
|
|
|
|
- At the bundled PromptKit adapter/command boundary, deliberately provide the
|
|
|
|
|
|
relevant native operation failure explanation, using the owning API's public
|
|
|
|
|
|
presentation and disclosure rules. Cover validation and the other native
|
|
|
|
|
|
inspection/selection paths affected by the same migration.
|
|
|
|
|
|
- Preserve the original cause independently and preserve an explicitly supplied
|
|
|
|
|
|
provider explanation. Keep independent warnings separate and avoid presenting
|
|
|
|
|
|
the same native failure through two paths.
|
|
|
|
|
|
- Keep core's cause-neutral behavior. Do not solve this by printing arbitrary
|
|
|
|
|
|
`Outcome.Cause` values or treating every application-owned loader/provider
|
|
|
|
|
|
error as safe operator text.
|
|
|
|
|
|
|
|
|
|
|
|
### Acceptance evidence
|
|
|
|
|
|
|
|
|
|
|
|
Use controlled upstream failure evidence to verify that CommandKit forwards
|
|
|
|
|
|
useful native failure content into the terminal explanation in ordinary and
|
|
|
|
|
|
quiet modes, with cause identity retained and unrelated warnings still hidden
|
|
|
|
|
|
where selected. Check explicit provider explanations for single presentation.
|
|
|
|
|
|
These are adapter/presentation assertions, not tests of whether PromptKit
|
|
|
|
|
|
correctly detects missing artifacts or invalid selections.
|
|
|
|
|
|
|
|
|
|
|
|
## 2. Retain independent rendering errors joined with write errors
|
|
|
|
|
|
|
2026-10-26 14:27:24 +00:00
|
|
|
|
Priority: P2. Status: complete.
|
|
|
|
|
|
|
|
|
|
|
|
- [x] Completed: joined callback errors retain independent rendering evidence,
|
|
|
|
|
|
while plain and wrapped sink errors remain write failures. Output and detail
|
|
|
|
|
|
regressions pass, including joined destination errors.
|
|
|
|
|
|
Validation: `GOTOOLCHAIN=local go test ./...` in the repository root.
|
2026-10-26 12:41:36 +00:00
|
|
|
|
|
|
|
|
|
|
### Finding and evidence
|
|
|
|
|
|
|
|
|
|
|
|
In [reporter.go](../../reporter.go), `recordRendererErrorLocked` drops the entire
|
|
|
|
|
|
callback error whenever `errors.Is(renderErr, writeErr)` is true. That test also
|
|
|
|
|
|
matches `errors.Join(independentRenderErr, writeErr)`: the callback error can
|
|
|
|
|
|
contain an independent rendering failure as well as the propagated sink failure.
|
|
|
|
|
|
|
|
|
|
|
|
The shared helper serves `RenderOutput`, message details, and terminal details.
|
|
|
|
|
|
Dropping the whole joined error loses evidence both from the immediate returned
|
|
|
|
|
|
error and from `Presentation.*.RenderError`.
|
|
|
|
|
|
|
|
|
|
|
|
A public-API audit consumer used a failing result writer and this callback:
|
|
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
|
_, writeErr := io.WriteString(w, "result")
|
|
|
|
|
|
return errors.Join(renderErr, writeErr)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The invocation failed as expected and retained the sink error, but
|
|
|
|
|
|
`errors.Is(returnedError, renderErr)` was false and the final output `RenderError`
|
|
|
|
|
|
was nil. This contradicts the selected retention of independently returned
|
|
|
|
|
|
rendering failures. The current separation test covers returning a standalone
|
|
|
|
|
|
rendering error after a failed write, but not a callback that already joins them.
|
|
|
|
|
|
|
|
|
|
|
|
### Required work
|
|
|
|
|
|
|
|
|
|
|
|
- Distinguish a callback merely propagating its managed-writer failure from a
|
|
|
|
|
|
callback carrying additional independent error evidence. Do not discard the
|
|
|
|
|
|
entire returned error just because its chain also contains the sink error.
|
|
|
|
|
|
- Preserve the independent callback error in the immediate error result and
|
|
|
|
|
|
bounded rendering observations. Retain the first write error separately and
|
|
|
|
|
|
continue avoiding further writes to the failed destination.
|
|
|
|
|
|
- Keep ordinary propagation of a write error from being misclassified as an
|
|
|
|
|
|
independently discovered rendering failure. No transcript or new public
|
|
|
|
|
|
error-classification API is needed.
|
|
|
|
|
|
|
|
|
|
|
|
### Acceptance evidence
|
|
|
|
|
|
|
|
|
|
|
|
Add a focused joined-error regression at the shared reporting boundary. Verify
|
|
|
|
|
|
`errors.Is` access to both failures in the returned error, rendering evidence in
|
|
|
|
|
|
`RenderError`, and sink evidence in `WriteError`. Preserve existing coverage for
|
|
|
|
|
|
plain/wrapped write-error propagation and first-error retention. Exercise a
|
|
|
|
|
|
detail-rendering path as needed to establish that the shared fix applies there.
|
|
|
|
|
|
|
|
|
|
|
|
## 3. Explain failures introduced by CommandKit presentation
|
|
|
|
|
|
|
2026-10-26 14:28:58 +00:00
|
|
|
|
Priority: P2. Status: complete.
|
|
|
|
|
|
|
|
|
|
|
|
- [x] Completed: presentation failures that turn success into failure now retain
|
|
|
|
|
|
a core-owned rendering/delivery explanation. Supplied explanations and causes,
|
|
|
|
|
|
generic handler fallback, quiet rendering, domain status, and failed-sink
|
|
|
|
|
|
behavior remain covered. Validation: `GOTOOLCHAIN=local go test ./...` at root.
|
2026-10-26 12:41:36 +00:00
|
|
|
|
|
|
|
|
|
|
### Finding and evidence
|
|
|
|
|
|
|
|
|
|
|
|
[Reporter.finalize](../../reporter.go) changes an otherwise successful outcome
|
|
|
|
|
|
to failure when presentation failed, then invokes the same
|
|
|
|
|
|
`ensureFallbackExplanation` used for an unexplained failed handler outcome.
|
|
|
|
|
|
Consequently, a CommandKit-invoked renderer failure or a result-write failure
|
|
|
|
|
|
produces only:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
ERROR: Command failed.
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The diagnostic destination may be entirely healthy. The caller can inspect
|
|
|
|
|
|
`Presentation`, but the operator is not told that rendering or delivery failed.
|
|
|
|
|
|
This also affects successful domain outcomes changed to non-zero status.
|
|
|
|
|
|
|
|
|
|
|
|
Public-API consumers reproduced the generic explanation after both a callback
|
|
|
|
|
|
that failed before writing and a rejected result write. The corresponding
|
|
|
|
|
|
reporter and execution tests currently assert this generic text, so they preserve
|
|
|
|
|
|
the gap rather than the selected distinction.
|
|
|
|
|
|
|
|
|
|
|
|
[Stage 4](implementation.md#stage-4-implement-deferred-delivery-and-finalization)
|
|
|
|
|
|
requires a useful core-owned explanation when presentation turns success into
|
|
|
|
|
|
failure. The roadmap assigns handling of reporting failures to CommandKit and
|
|
|
|
|
|
distinguishes healthy diagnostic destinations from failed result destinations.
|
|
|
|
|
|
The generic fallback remains appropriate for a failed handler outcome that
|
|
|
|
|
|
supplies no explanation; it does not explain the presentation failure core
|
|
|
|
|
|
itself discovered.
|
|
|
|
|
|
|
|
|
|
|
|
### Required work
|
|
|
|
|
|
|
|
|
|
|
|
- When presentation changes a successful outcome into failure and no explanation
|
|
|
|
|
|
was supplied, attach and retain an explanation identifying the failed
|
|
|
|
|
|
presentation operation, such as result rendering or result delivery. Present
|
|
|
|
|
|
it through a healthy diagnostic destination.
|
|
|
|
|
|
- Keep the original optional cause unchanged and preserve supplied explanations.
|
|
|
|
|
|
An informative core-owned heading is sufficient; this does not require
|
|
|
|
|
|
automatically exposing callback error strings or application causes.
|
|
|
|
|
|
- Preserve the selected outcome/status table, exact generic fallback for
|
|
|
|
|
|
otherwise unexplained failed outcomes, and explicit native explanations,
|
|
|
|
|
|
including a non-nil renderer that emits no bytes.
|
|
|
|
|
|
- Do not retry a failed diagnostic destination, redirect into substantive output,
|
|
|
|
|
|
replay explanation callbacks, or introduce recursive reporting-failure messages.
|
|
|
|
|
|
|
|
|
|
|
|
### Acceptance evidence
|
|
|
|
|
|
|
|
|
|
|
|
Update focused tests so a successful operation with an output-rendering or
|
|
|
|
|
|
output-writing failure receives a retained presentation-specific explanation
|
|
|
|
|
|
through working diagnostics, including quiet rendering failure and a successful
|
|
|
|
|
|
domain outcome. Preserve evidence for supplied explanations/causes, generic
|
|
|
|
|
|
fallback on unexplained handler failure, and diagnostic-sink failure without
|
|
|
|
|
|
retry. Assert the meaningful failure category rather than inventing a new
|
|
|
|
|
|
public exact-wording guarantee.
|
2026-10-26 14:01:28 +00:00
|
|
|
|
|
|
|
|
|
|
## 4. Restore cancellation checks between report preparation and delivery
|
|
|
|
|
|
|
2026-10-26 14:32:03 +00:00
|
|
|
|
Priority: P2. Status: complete.
|
|
|
|
|
|
|
|
|
|
|
|
- [x] Completed: restored preparation-before-delivery cancellation checks for
|
|
|
|
|
|
PromptKit catalogs, definitions, requirements, and validation, and buffered
|
|
|
|
|
|
configuration diff/sources/YAML explanation reports. Cancellation retains its
|
|
|
|
|
|
operation cause without becoming a rendering failure; native streaming and
|
|
|
|
|
|
smoke-report behavior remain unchanged. Controlled preparation/serialization
|
|
|
|
|
|
checks cover ordinary and quiet modes. Validation: module suites pass in
|
|
|
|
|
|
`integrations/ckconfig` and `integrations/ckprompt`.
|
2026-10-26 14:01:28 +00:00
|
|
|
|
|
|
|
|
|
|
### Finding and evidence
|
|
|
|
|
|
|
|
|
|
|
|
Before the reporting migration, PromptKit's `writePromptReport` checked the
|
|
|
|
|
|
invocation context after a report had been prepared and before writing it.
|
|
|
|
|
|
The migrated [renderProfileReport](../../integrations/ckprompt/command.go)
|
|
|
|
|
|
formats its text report inside `RenderOutput`, writes it immediately, and
|
|
|
|
|
|
returns success without that intervening cancellation check. The surrounding
|
|
|
|
|
|
inspection command checks cancellation only before entering report preparation.
|
|
|
|
|
|
|
|
|
|
|
|
A deterministic public-API consumer supplied a profile inspection with a
|
|
|
|
|
|
controlled YAML marshaler in `EffectiveModelParams.ExtraParams`. The marshaler
|
|
|
|
|
|
cancelled the invocation context and returned a valid value while the text
|
|
|
|
|
|
report was being prepared. This uses the ordinary report serialization boundary;
|
|
|
|
|
|
it does not reenter the reporter or require concurrency or an external service.
|
|
|
|
|
|
|
|
|
|
|
|
Observed results for `promptkit show profile demo --format text`:
|
|
|
|
|
|
|
|
|
|
|
|
| Mode | Context at completion | Status | Cause matches cancellation | Report bytes |
|
|
|
|
|
|
| --- | --- | --- | --- | --- |
|
|
|
|
|
|
| Ordinary | `context.Canceled` | `0` | No | `277` |
|
|
|
|
|
|
| Quiet | `context.Canceled` | `0` | No | `0` |
|
|
|
|
|
|
|
|
|
|
|
|
Cancellation occurred before the first destination write. Previously, the shared
|
|
|
|
|
|
post-preparation check would have returned operational failure with the
|
|
|
|
|
|
cancellation cause and left the report destination untouched. The migration also
|
|
|
|
|
|
removed similar post-preparation checks from buffered configuration report paths,
|
|
|
|
|
|
including [config diff](../../integrations/ckconfig/diff.go). Its current
|
|
|
|
|
|
post-render cancellation branch runs only when rendering already returned an
|
|
|
|
|
|
error, so successful preparation does not preserve the old checkpoint.
|
|
|
|
|
|
|
|
|
|
|
|
The plan requires preserving existing cancellation behavior outside the selected
|
|
|
|
|
|
reporting changes. Quiet suppression is not intended to turn this cancellation
|
|
|
|
|
|
into success. Existing cancellation tests cover acquisition and write failures,
|
|
|
|
|
|
but do not cover cancellation during successful report preparation.
|
|
|
|
|
|
|
|
|
|
|
|
### Required work
|
|
|
|
|
|
|
|
|
|
|
|
- Restore the integration-owned cancellation checkpoint after report preparation
|
|
|
|
|
|
and before delivery in migrated paths that previously had it. Review the
|
|
|
|
|
|
removed `writePromptReport` callers and the buffered configuration paths rather
|
|
|
|
|
|
than patching only the demonstrated profile-text case.
|
|
|
|
|
|
- Preserve supported cancellation identity in the operation outcome, while
|
|
|
|
|
|
retaining reporter ownership of rendering and destination failures. Apply the
|
|
|
|
|
|
same operation decision under quiet mode.
|
|
|
|
|
|
- Keep this change bounded to the existing preparation/delivery behavior. Do not
|
|
|
|
|
|
introduce a core-wide rule that rejects every cancelled application invocation,
|
|
|
|
|
|
interrupt caller writers, withdraw delivered bytes, or promise cancellation
|
|
|
|
|
|
after delivery has already begun. New whole-run buffering is unnecessary.
|
|
|
|
|
|
|
|
|
|
|
|
### Acceptance evidence
|
|
|
|
|
|
|
|
|
|
|
|
Use a controlled serialization/preparation callback to cancel before the first
|
|
|
|
|
|
report write. Assert operational failure, `errors.Is` access to
|
|
|
|
|
|
`context.Canceled`, and no report delivery, including quiet mode. This verifies
|
|
|
|
|
|
CommandKit coordination, not upstream serialization or domain behavior. Preserve
|
|
|
|
|
|
existing coverage for cancellation during acquisition, partial output, and
|
|
|
|
|
|
caller-owned writes that have already started.
|
|
|
|
|
|
|
|
|
|
|
|
## 5. Apply reporting-flag aliases in unresolved-route parse contexts
|
|
|
|
|
|
|
2026-10-26 14:33:31 +00:00
|
|
|
|
Priority: P2. Status: complete.
|
|
|
|
|
|
|
|
|
|
|
|
- [x] Completed: unresolved routes obtain aliases from the context selected by
|
|
|
|
|
|
normal parsing, through neutral internal metadata. Root and nested-group
|
|
|
|
|
|
canonical/alias comparisons, quiet failure visibility, scoped precedence,
|
|
|
|
|
|
unchanged unresolved identity, and factory non-execution pass.
|
|
|
|
|
|
Validation: `GOTOOLCHAIN=local go test ./...` at the repository root.
|
2026-10-26 14:01:28 +00:00
|
|
|
|
|
|
|
|
|
|
### Finding and evidence
|
|
|
|
|
|
|
|
|
|
|
|
[compileFlagAliases](../../flag_aliases.go) now resolves application-wide aliases
|
|
|
|
|
|
to the new reporting flags in root and group contexts. However,
|
|
|
|
|
|
[execution.prepareSession](../../execute.go) supplies aliases to the parser only
|
|
|
|
|
|
for `routeCanonical` and `routeDiscovery`. For an unresolved command path it
|
|
|
|
|
|
supplies none, even when the normal parser selects the root or a known group
|
|
|
|
|
|
whose reporting flags and alias mappings are available.
|
|
|
|
|
|
|
|
|
|
|
|
With an installed application-wide `FlagAlias("-d", "--debug")`, a public-API
|
|
|
|
|
|
consumer reproduced:
|
|
|
|
|
|
|
|
|
|
|
|
| Invocation | Observed diagnostics |
|
|
|
|
|
|
| --- | --- |
|
|
|
|
|
|
| `app missing --debug` | Debug route/selection detail, then the unknown-command usage failure. |
|
|
|
|
|
|
| `app missing -d` | `unknown shorthand flag: 'd' in -d`, with no Debug detail. |
|
|
|
|
|
|
| `app group missing --debug` | Debug detail, then the group operand/command usage failure. |
|
|
|
|
|
|
| `app group missing -d` | `unknown shorthand flag: 'd' in -d`, with no Debug detail. |
|
|
|
|
|
|
| `app group run -d` | Successful command execution with Debug detail. |
|
|
|
|
|
|
|
|
|
|
|
|
The spelling registered for a reporting flag is thus treated as unknown on the
|
|
|
|
|
|
failure paths where operators may need debugging. Canonical mode selection on
|
|
|
|
|
|
these paths already works. This conflicts with the
|
|
|
|
|
|
[CLI alias contract](../cli.md#application-owned-aliases): an application-wide
|
|
|
|
|
|
alias is effective wherever its canonical target is available. The new reporting
|
|
|
|
|
|
flags make these existing parse-context gaps observable for mode selection.
|
|
|
|
|
|
|
|
|
|
|
|
Current reporting parse tests cover a canonical reporting flag after a missing
|
|
|
|
|
|
command and aliases on valid routes, but not their combination.
|
|
|
|
|
|
|
|
|
|
|
|
### Required work
|
|
|
|
|
|
|
|
|
|
|
|
- Supply the alias mapping applicable to the context used by normal parsing
|
|
|
|
|
|
when the full entered command path does not resolve. Cover root and known
|
|
|
|
|
|
group parse contexts, preserving existing scope/precedence rules where they
|
|
|
|
|
|
apply.
|
|
|
|
|
|
- Keep ordered canonical/alias occurrence handling in the normal parser. Do not
|
|
|
|
|
|
add a separate reporting-flag scanner or enable unrelated aliases whose
|
|
|
|
|
|
canonical target is unavailable.
|
|
|
|
|
|
- Preserve the original routing failure, handler/factory non-execution, and
|
|
|
|
|
|
entered-path usage behavior. Finding a parse context must not manufacture a
|
|
|
|
|
|
successfully resolved canonical command identity for the invalid route.
|
|
|
|
|
|
|
|
|
|
|
|
### Acceptance evidence
|
|
|
|
|
|
|
|
|
|
|
|
Compare canonical and application-wide aliased reporting flags on unresolved
|
|
|
|
|
|
root and nested-group paths. They should select the same mode and retain the
|
|
|
|
|
|
same underlying command-path failure rather than invent an unknown-flag error.
|
|
|
|
|
|
Include a quiet alias followed by another parse error, without suppressing the
|
|
|
|
|
|
terminal usage explanation. Retain scoped-alias precedence, unavailable-target,
|
|
|
|
|
|
terminator/value handling, and discovery-context coverage at their existing
|
|
|
|
|
|
owners.
|
2026-10-26 14:14:50 +00:00
|
|
|
|
|
|
|
|
|
|
## 6. Avoid retaining deferred messages that need no presentation work
|
|
|
|
|
|
|
|
|
|
|
|
Priority: P3. Status: for consideration.
|
|
|
|
|
|
|
|
|
|
|
|
### Finding and complexity
|
|
|
|
|
|
|
|
|
|
|
|
[DeferredReporter.enqueue](../../reporter.go) unconditionally stores the category,
|
|
|
|
|
|
heading, and copied detail list. Visibility is checked only when `finalize`
|
|
|
|
|
|
drains the queue through `submitMessage`. Consequently, a long-running handler
|
|
|
|
|
|
that submits many simple deferred Debug messages in ordinary mode, or simple
|
|
|
|
|
|
Info/Warning messages in quiet mode, retains all of them despite there being
|
|
|
|
|
|
no output or renderer work to perform.
|
|
|
|
|
|
|
|
|
|
|
|
Let `M` be the number of these renderer-free hidden messages and `B` the bytes
|
|
|
|
|
|
of otherwise unreferenced distinct heading text. Reporter storage can grow as
|
|
|
|
|
|
`Θ(M + B)` until finalization. Finalization then makes a second `Θ(M)` queue
|
|
|
|
|
|
array copy before visiting and suppressing every entry. This is linear, not
|
|
|
|
|
|
quadratic, but the additional reporter storage for this case can be `O(1)`.
|
|
|
|
|
|
The `M` public submissions still require `Θ(M)` total call work; this is not a
|
|
|
|
|
|
claim that the whole invocation can become sublinear.
|
|
|
|
|
|
|
|
|
|
|
|
### Refactoring opportunity
|
|
|
|
|
|
|
|
|
|
|
|
Under the current execution flow, reporting selection is applied before handlers
|
|
|
|
|
|
and providers run, with no public operation to change it mid-handler. For a
|
|
|
|
|
|
hidden deferred submission with no non-nil detail callback, consider recording
|
|
|
|
|
|
the eventual suppression observation without retaining the heading or queue
|
|
|
|
|
|
entry. Preserve the existing no-content treatment of an empty heading with no
|
|
|
|
|
|
renderer. This removes the avoidable `Θ(M + B)` retention and its later sweep
|
|
|
|
|
|
for renderer-free suppressed messages.
|
|
|
|
|
|
|
|
|
|
|
|
Retain rich hidden submissions: their callbacks must still execute at the
|
|
|
|
|
|
selected deferred time against discard so rendering failures are preserved.
|
|
|
|
|
|
Retain visible messages in FIFO order. Closed-reporter checks must still run
|
|
|
|
|
|
before accepting or discarding any submission. This optimization does not add
|
|
|
|
|
|
a public immutability guarantee for future mode APIs or change the selected
|
|
|
|
|
|
emission-time visibility rules.
|
|
|
|
|
|
|
|
|
|
|
|
Independently, `finalize` can detach the reporter-owned queue under its existing
|
|
|
|
|
|
mutex instead of copying its array and then clearing the original reference.
|
|
|
|
|
|
That makes queue handoff `O(1)` instead of `Θ(M)` extra copying; actual visible/
|
|
|
|
|
|
rich message delivery remains linear. An internal delivery path can also avoid
|
|
|
|
|
|
recopying callback lists already captured by `enqueue`, while preserving the
|
|
|
|
|
|
selected defensive copy when first accepting caller-owned lists.
|
|
|
|
|
|
|
|
|
|
|
|
These opportunities preserve the chosen queue and synchronous delivery model.
|
|
|
|
|
|
They do not justify message caps, dropping visible messages, skipping rich
|
|
|
|
|
|
renderers, or a background delivery subsystem.
|
|
|
|
|
|
|
|
|
|
|
|
### Review evidence
|
|
|
|
|
|
|
|
|
|
|
|
The retention and copies follow directly from `enqueue`, the array copy at the
|
|
|
|
|
|
start of `finalize`, and `submitMessage`'s later visibility check. If selected,
|
|
|
|
|
|
use focused behavior checks for suppression observations, FIFO delivery,
|
|
|
|
|
|
callback capture, hidden renderer failures, and late submissions. Source-level
|
|
|
|
|
|
storage analysis is sufficient; no benchmark or allocation threshold is proposed.
|
|
|
|
|
|
|
|
|
|
|
|
## 7. Stop normalizing an argument tail that parsing cannot reach
|
|
|
|
|
|
|
|
|
|
|
|
Priority: P3. Status: for consideration.
|
|
|
|
|
|
|
|
|
|
|
|
### Finding and complexity
|
|
|
|
|
|
|
|
|
|
|
|
In [interpretFlagTokens](../../internal/cobra/flags.go), the first unknown long
|
|
|
|
|
|
flag or unknown short-cluster member sets `recordingOccurrences = false`, but
|
|
|
|
|
|
interpretation continues through the remaining argv. Later recognized flags
|
|
|
|
|
|
still populate spelling lists and construct canonical `--name=value` strings.
|
|
|
|
|
|
[Session.Parse](../../internal/cobra/parse.go) then calls the backend, which
|
|
|
|
|
|
fails at the earlier unknown flag without consuming that normalized tail.
|
|
|
|
|
|
The adapter does not enable unknown-flag whitelisting.
|
|
|
|
|
|
|
|
|
|
|
|
For example, after `--unknown`, a later valid `--message=LARGE_VALUE` still
|
|
|
|
|
|
causes the value bytes to be copied into a new canonical argument, even though
|
|
|
|
|
|
no parser, converter, or handler reaches that value. The recent occurrence
|
|
|
|
|
|
tracking correctly excludes the tail from selection evidence but retains this
|
|
|
|
|
|
pre-existing unnecessary normalization work.
|
|
|
|
|
|
|
|
|
|
|
|
Let `F` and `A` be the flag/alias table sizes, `P` the token/byte processing cost
|
|
|
|
|
|
through the first fatal unknown flag, and `T` the remaining normalization work,
|
|
|
|
|
|
including copied value bytes. With expected constant-time map lookups, the helper
|
|
|
|
|
|
currently takes `O(F + A + P + T)` time on that failure path. It can take
|
|
|
|
|
|
`O(F + A + P)` by stopping at the failing token and growing temporary arrays
|
|
|
|
|
|
with the prefix instead of preallocating for all argv. The existing backend can
|
|
|
|
|
|
still produce the same failure from that prefix. This is an early-failure
|
|
|
|
|
|
improvement, not a quadratic-time finding or a change to the successful parse's
|
|
|
|
|
|
necessary linear work.
|
|
|
|
|
|
|
|
|
|
|
|
### Refactoring opportunity
|
|
|
|
|
|
|
|
|
|
|
|
Consider ending interpretation immediately after preserving the first unknown
|
|
|
|
|
|
flag or failing short-cluster suffix. Preserve any earlier valid occurrences and
|
|
|
|
|
|
their spellings, including recognized members preceding a bad short member.
|
|
|
|
|
|
Let the backend retain its existing failure classification, wording, and
|
|
|
|
|
|
precedence; do not replace normal parsing with a reporting-specific scanner.
|
|
|
|
|
|
This can also remove the repeated `recordingOccurrences` guards needed solely
|
|
|
|
|
|
because the current implementation continues past the failure.
|
|
|
|
|
|
|
|
|
|
|
|
The helper currently preallocates both output and occurrence slices from total
|
|
|
|
|
|
argv length, so an early return alone does not eliminate its `O(argc)` upfront
|
|
|
|
|
|
array allocation and initialization. To obtain the prefix-bounded helper cost,
|
|
|
|
|
|
grow those arrays with the interpreted prefix rather than reserving for the
|
|
|
|
|
|
unreachable tail. This changes allocation strategy, not accepted input sizes.
|
|
|
|
|
|
|
|
|
|
|
|
Other routing/parser steps still copy argv string headers, so this refactoring
|
|
|
|
|
|
does not make the entire invocation prefix-linear. It specifically removes
|
|
|
|
|
|
avoidable tail interpretation, spelling storage, and large-value byte copies.
|
|
|
|
|
|
There is no need to reconsider the selected backend or fresh-tree strategy.
|
|
|
|
|
|
|
|
|
|
|
|
### Review evidence
|
|
|
|
|
|
|
|
|
|
|
|
The unknown-flag branches and continued spelling/string construction establish
|
|
|
|
|
|
the extra work statically. Existing prefix-order, missing-value precedence,
|
|
|
|
|
|
short-cluster, and terminator/value tests provide relevant behavior coverage if
|
|
|
|
|
|
this is selected. Preserve the backend error and consumed occurrence prefix on
|
|
|
|
|
|
early failure; no timing threshold or real-world performance data is needed.
|