Complete the Stage 22 efficiency audit
This commit is contained in:
@@ -325,7 +325,7 @@ inventory commands, graph index refresh, and graph architecture inspection.
|
||||
| 19 | Audit test hermeticity and execution hygiene | Complete |
|
||||
| 20 | Audit test risk coverage and ownership | Complete |
|
||||
| 21 | Audit test durability, duplication, and maintenance cost | Complete |
|
||||
| 22 | Audit cross-cutting efficiency and complexity | Pending |
|
||||
| 22 | Audit cross-cutting efficiency and complexity | Complete |
|
||||
| 23 | Audit cross-cutting refactoring and deduplication opportunities | Pending |
|
||||
| 24 | Audit documentation coherence and executable contracts | Pending |
|
||||
| 25 | Run dynamic robustness and final diagnostic validation | Pending |
|
||||
@@ -359,7 +359,8 @@ with evidence about meaningful risks, test ownership, gaps, and duplication.
|
||||
| Test hermeticity and execution hygiene | All Go tests, fixtures, test assets, and helper mechanisms | 19 | Partly insufficient. The suite is offline, uses controlled clocks/roots/environment for almost every stateful case, has no subprocesses or automatic golden updates, passes race and shuffled-repeat checks, and succeeds with a scrubbed environment and broken external proxies. `AUD-059` records one ambient credential assumption; `AUD-060` records unguarded symlink-capability assumptions. |
|
||||
| Test risk coverage and ownership | Repository-wide suite | 20 | Partly insufficient. Consequential contracts have narrow owners and representative cross-boundary workflows; every identified missing regression is already attached to the production or test-gap finding for the defect it would catch. Coverage diagnostics found no additional unowned critical branch. Accepted omissions are thin entry-point/delegation wrappers, defensive accessors, and dormant helpers already routed under `AUD-001`; broad duplication and durability remain Stage 21. |
|
||||
| Test durability, duplication, and maintenance cost | Repository-wide suite | 21 | Partly insufficient. Most tests assert stable behavior with direct fixtures and appropriately narrow fakes. `AUD-039`, `AUD-061`, and `AUD-063` identify duplicated or implementation-coupled assertions; `AUD-062` identifies avoidable production waits; `AUD-064` identifies incomplete failure cleanup. Each consolidation retains a named behavioral owner. |
|
||||
| Cross-cutting efficiency and maintainability | Graph metrics plus focused tests | 22-23 | Pending |
|
||||
| Cross-cutting efficiency | Graph metrics, workflow traces, and focused latency/allocation diagnostics | 22 | Partly insufficient. Fixed-size registries, service-sized derivation, template parsing, batch composition, and ordinary profile fan-out are proportionate. `AUD-065` records one redundant Weather API request plus serial independent source fetches; `AUD-066` records repeated full comparison-bundle reads during replacement. |
|
||||
| Cross-cutting maintainability | Graph metrics plus focused structural review | 23 | Pending |
|
||||
| Documentation and executable-contract coherence | Canonical documents, code, schemas, templates, examples | 24 | Pending |
|
||||
| Dynamic robustness and diagnostic checks | Repository-wide deterministic checks | 25 | Pending |
|
||||
|
||||
@@ -2805,6 +2806,97 @@ with evidence about meaningful risks, test ownership, gaps, and duplication.
|
||||
- Related findings: `AUD-058`
|
||||
- Remediation reference: pending
|
||||
|
||||
### AUD-065: Weather collection duplicates one source and serializes independent requests
|
||||
|
||||
- Stage: 22
|
||||
- Status: candidate
|
||||
- Severity: medium
|
||||
- Confidence: high
|
||||
- Category: efficiency
|
||||
- Area: `internal/adapters/weatherapi.Client.FetchBundle`, `warmup`, and the
|
||||
eight `bundleBuilder.fetch*` calls
|
||||
- Evidence: Every collection first performs a warmup GET against the default
|
||||
`/conditions/current` endpoint, discards its body, and immediately fetches
|
||||
`/conditions/current` again as one of eight source products. The remaining
|
||||
seven products are independent HTTP endpoints, but `FetchBundle` waits for
|
||||
all eight in a fixed serial chain. A temporary controlled diagnostic added
|
||||
25 milliseconds of server latency to every healthy endpoint: five runs took
|
||||
236-240 milliseconds apiece, made nine requests, and requested current
|
||||
conditions twice. The diagnostic was removed after measurement.
|
||||
- Contract at risk: Collection should preserve source policy, deterministic
|
||||
normalized output, and prompt cancellation without making healthy latency
|
||||
the sum of independent network round trips or issuing a request whose data
|
||||
is always discarded.
|
||||
- Impact: For approximately equal endpoint latency `L`, the current healthy
|
||||
transport floor is about `9L`; one full `L` and one upstream response are
|
||||
unconditionally redundant, while serialization adds roughly another `7L`
|
||||
over concurrent independent acquisition. Generate, each batch, and each
|
||||
comparison collect once, so every user-visible workflow pays this cost even
|
||||
though later model latency is separate. Slow optional products also delay
|
||||
all otherwise usable source results and their eventual policy decision.
|
||||
- Recommendation: Remove the duplicate current-conditions warmup, or make the
|
||||
successful current fetch satisfy readiness as well as collection. Acquire
|
||||
independent products with a bounded, cancellation-aware group into
|
||||
source-local results, then merge them in canonical source order so warning,
|
||||
provenance, required-source, and error-precedence behavior stays explicit.
|
||||
Do not share-mutate the current builder from request goroutines.
|
||||
- Test implications: Add a delayed local-server case proving independent
|
||||
requests overlap and current conditions are requested once. Retain focused
|
||||
cases for warmup/retry policy if a distinct readiness operation remains, and
|
||||
assert deterministic warning/provenance order, required-source failure,
|
||||
optional-source policy, cancellation, and worker joining.
|
||||
- Validation: A healthy collection performs only necessary requests and its
|
||||
post-readiness duration approaches the slowest independent source rather
|
||||
than their sum; existing normalized fixture output and failure policy remain
|
||||
byte-for-byte or semantically unchanged as appropriate.
|
||||
- Related findings: `AUD-013`, `AUD-015`
|
||||
- Remediation reference: pending
|
||||
|
||||
### AUD-066: Comparison replacement repeatedly rereads complete bundles
|
||||
|
||||
- Stage: 22
|
||||
- Status: candidate
|
||||
- Severity: low
|
||||
- Confidence: high
|
||||
- Category: efficiency
|
||||
- Area: `internal/app.compareDetailed`,
|
||||
`internal/comparison.PlanDestination`, `RecognizeBundle`, and `publish`
|
||||
- Evidence: Replacing an existing bundle invokes `PlanDestination` before
|
||||
prompt work, again after execution, at entry to `publish`, and once more at
|
||||
the commit boundary. Every nonempty replacement plan calls
|
||||
`RecognizeBundle`. One recognition reads the manifest once to decode it,
|
||||
reads every declared directory entry in full (including that manifest and
|
||||
the data package), then reads the data package a second time for its digest.
|
||||
For `N` successful reports, one ordinary replacement therefore performs
|
||||
four recognitions and `4N+16` complete file reads: even a two-profile bundle
|
||||
causes 24 reads, while a ten-profile bundle causes 56. Each report is read
|
||||
four times and the manifest and data package eight times.
|
||||
- Contract at risk: Early destination rejection and commit-time
|
||||
reauthorization are necessary, but each authorization pass should perform
|
||||
only the content work needed to establish the recognized-bundle invariant.
|
||||
- Impact: Small local bundles make the overhead modest, but the cost scales
|
||||
linearly with profile count and full artifact size, including generated
|
||||
Markdown already unbounded under `AUD-038`. Replacement on slower or remote
|
||||
filesystems multiplies both I/O and pre-publication latency; the adjacent
|
||||
post-execution and publisher-entry checks repeat the same scan with almost
|
||||
no intervening stateful work.
|
||||
- Recommendation: Preserve one early preflight and a final commit-time
|
||||
reauthorization, but remove or combine adjacent ownership checks after
|
||||
defining which layer owns each. Within recognition, decode the manifest and
|
||||
hash the data package from their first reads, and validate report entries by
|
||||
metadata plus a minimal open/readability check unless the bundle contract
|
||||
adds report-content digests. Keep the final namespace/type checks needed by
|
||||
the existing replacement threat model.
|
||||
- Test implications: Instrument file-open/read operations or use a focused
|
||||
filesystem seam to assert bounded passes for two and many reports. Retain
|
||||
all current symlink, unexpected-entry, digest, concurrent replacement,
|
||||
rollback, and commit-time reauthorization cases.
|
||||
- Validation: Replacement performs one deliberate early scan and one
|
||||
deliberate commit authorization without rereading any artifact inside a
|
||||
scan; recognized and adversarial bundles retain their current outcomes.
|
||||
- Related findings: `AUD-038`, `AUD-053`, `AUD-055`
|
||||
- Remediation reference: pending
|
||||
|
||||
## Retained Decisions
|
||||
|
||||
### RET-001: Keep the application package as the explicit composition owner
|
||||
@@ -3382,6 +3474,47 @@ template changes reviewable without memorializing incidental whitespace.
|
||||
Retain that style while consolidating the cross-owner render checks in
|
||||
`AUD-063`.
|
||||
|
||||
### RET-050: Keep service-sized derivation and registries straightforward
|
||||
|
||||
Graph loop propagation led through daily context construction into fact and
|
||||
forecast selection, but the concrete workload is bounded by four default
|
||||
dayparts and Weather API runs of a few hundred periods. The work is linear per
|
||||
selection, and Stage 7 already counted only low-thousands of simple overlap
|
||||
checks for an ordinary derived build. Report and generated-text registries
|
||||
contain four definitions, while the module registry is a fixed small catalog;
|
||||
rebuilding those values is not a credible hot path at current cardinalities.
|
||||
Retain the direct loops and explicit registries. Reconsider indexing or caching
|
||||
only if forecast horizons, configured dayparts, or registries become dynamic
|
||||
and materially larger.
|
||||
|
||||
### RET-051: Keep embedded template parsing until render volume changes
|
||||
|
||||
`reporttemplate.Render` reads and parses one top-level template plus four
|
||||
embedded partials on each call. A temporary benchmark that deliberately
|
||||
reached execution failure only after parsing measured 0.283-0.291 milliseconds
|
||||
and about 91 KiB across 1,898 allocations per render on the audit host. The
|
||||
fixed three-report batches therefore spend under one millisecond parsing, and
|
||||
ordinary comparisons select only a handful of profiles; provider execution is
|
||||
orders of magnitude slower. Keep the simple per-call ownership and error
|
||||
context for now. A pre-parsed immutable set becomes justified if rendering
|
||||
moves into a high-volume service loop or profiles routinely number in the
|
||||
hundreds. The benchmark file was removed after measurement.
|
||||
|
||||
### RET-052: Keep prepare-once profile execution and fixed batch sequencing
|
||||
|
||||
Comparison builds facts, modules, and prompt input once, then starts one
|
||||
profile-local execution per explicitly selected profile; the durable order is
|
||||
held in a preallocated result slice and Promptkit owns provider capacity.
|
||||
Per-profile JSON cloning and rendering provide mutation isolation, while the
|
||||
documented and example workload is a human-selected comparison of at least two
|
||||
profiles rather than an unbounded service queue. Morning and evening batches
|
||||
likewise contain a fixed small report set and intentionally preserve
|
||||
independent sequential publication before one notification. Retain both
|
||||
designs at current workload. Treat routine selections in the tens or hundreds,
|
||||
observable clone contention, or a larger dynamic batch as triggers for a
|
||||
bounded worker design rather than inferring a defect from goroutine or graph
|
||||
counts alone.
|
||||
|
||||
## Open Questions
|
||||
|
||||
No Stage 1 open questions or unexplained baseline failures remain.
|
||||
@@ -3757,6 +3890,25 @@ Stage 21 routed these investigation leads to their assigned later stages:
|
||||
recorded by Stage 20; Stage 21 did not treat it as a durability or test-count
|
||||
issue.
|
||||
|
||||
Stage 22 routed these investigation leads to their assigned later stages:
|
||||
|
||||
- Fixed registries are cheap but are reconstructed through several public
|
||||
helpers. Stage 23 should decide ownership and API shape from duplication and
|
||||
coherence evidence, not introduce caches for a performance problem Stage 22
|
||||
did not find.
|
||||
- `AUD-065` needs deterministic error precedence and ordered provenance if
|
||||
acquisition becomes concurrent. Stage 23 may identify a small result-merge
|
||||
abstraction; Stage 26 should preserve Stage 6 source-policy findings instead
|
||||
of treating concurrency alone as the remediation.
|
||||
- `AUD-066` must retain early rejection and commit-time namespace
|
||||
reauthorization. Stage 23 should clarify app-versus-publisher ownership, and
|
||||
Stage 25 should exercise concurrent destination changes before Stage 26
|
||||
consolidates reads.
|
||||
- Profile fan-out remains proportionate for documented human-selected sets
|
||||
under `RET-052`. Stage 24 should not imply an arbitrary scalability promise;
|
||||
Stage 26 may consider a limit or worker bound only if operational evidence
|
||||
establishes a larger supported workload.
|
||||
|
||||
## Stage Log
|
||||
|
||||
### Stage 1: Establish The Baseline And Audit Ledger
|
||||
@@ -4931,3 +5083,56 @@ Stage 21 routed these investigation leads to their assigned later stages:
|
||||
- Retained decisions: `RET-047` through `RET-049`.
|
||||
- Open questions: the four leads recorded above are routed to their assigned
|
||||
later stages.
|
||||
|
||||
### Stage 22: Audit Cross-Cutting Efficiency And Complexity
|
||||
|
||||
- Status: Complete.
|
||||
- Scope reviewed: production graph complexity, fan-in/fan-out, loop depth, and
|
||||
repeated work; Weather API collection; forecast/fact/module construction;
|
||||
prompt-input serialization; generated-text validation and rendering;
|
||||
prepare-once execution; single and fixed-batch workflows; comparison profile
|
||||
fan-out; comparison bundle construction, recognition, and transactional
|
||||
publication; fixed registry construction; allocation and I/O boundaries; and
|
||||
realistic service, report, profile, and artifact cardinalities.
|
||||
- Exclusions: structural extraction, API simplification, and code deduplication
|
||||
remain Stage 23; documentation promises remain Stage 24; adversarial and
|
||||
dynamic robustness remain Stage 25; no remediation was implemented. No
|
||||
production code or tests were changed.
|
||||
|
||||
#### Efficiency And Workload Accounting
|
||||
|
||||
| Candidate | Realistic workload and measured/defensible cost | Disposition |
|
||||
| --- | --- | --- |
|
||||
| Weather source acquisition | Every workflow collects once. Healthy collection performs a discarded `/conditions/current` warmup, fetches current again, and serially fetches seven other independent products. With equal latency `L`, the transport floor is about `9L`. Five controlled 25-millisecond-delay runs took 236-240 milliseconds, made nine requests, and hit current twice. | Credible user-visible latency and redundant upstream work under `AUD-065`. |
|
||||
| Forecast and fact derivation | Weather runs contain a few hundred periods; four default dayparts cause low-thousands of simple linear overlap/selection checks. The graph's propagated depth of three or four reflects composed scans, not one polynomial nested loop over the same growing collection. | Proportionate under `RET-050`; no finding. |
|
||||
| Registry and catalog construction | Report/generated-text catalogs contain four definitions and the module catalog is fixed and small. Construction occurs per command/report boundary but does not grow with weather data or generated output. | Retain direct construction under `RET-050`; Stage 23 owns API/duplication questions. |
|
||||
| Prompt input and generated validation | One package is built and YAML-serialized per prepared report. Generated output is decoded, semantically normalized, and encoded once per execution; no runtime schema compiler or repeated schema parse exists. Payload-size risk is already `AUD-038`. | Linear necessary work; no separate efficiency finding. |
|
||||
| Template rendering | Every render reparses one template and four partials. A temporary parse-through-execution benchmark measured 0.283-0.291 ms and about 91 KiB/1,898 allocations per render. Fixed batches contain three reports and ordinary comparisons a handful of profiles. | Measurable but immaterial at supported volume; retain under `RET-051`. |
|
||||
| Prepared comparison fan-out | Facts/modules/input are prepared once. Each explicit profile receives isolated JSON-cloned render inputs, one render, and one result slot; one goroutine starts per profile while Promptkit owns provider capacity. Documentation and examples describe human-selected sets beginning at two profiles. | Proportionate at current scale under `RET-052`; watch tens/hundreds rather than inventing a metric-only limit. |
|
||||
| Fixed batch sequencing | Morning/evening batches collect once and sequentially prepare, execute, and publish a fixed three-report set before one notification. Provider calls dominate, but concurrency would change backend-capacity and partial-publication behavior for a bounded gain. | Retain under `RET-052`; no finding from sequentiality alone. |
|
||||
| Comparison replacement recognition | Existing recognized destinations are fully scanned four times. Each scan performs `N+4` full reads for `N` successful reports, so ordinary replacement performs `4N+16` reads: 24 for two profiles and 56 for ten. Reports are read four times; manifest and data package eight times. | Credible scaling and filesystem-I/O issue under `AUD-066`; preserve early and commit-time authorization. |
|
||||
|
||||
#### Commands And Evidence
|
||||
|
||||
- Used graph complexity queries, search, symbol snippets, and call traces to
|
||||
inspect the highest propagated loop depths and production fan-in/fan-out,
|
||||
then followed the concrete generate, batch, comparison, collection,
|
||||
derivation, rendering, and publication paths rather than treating graph
|
||||
scores as findings.
|
||||
- Reconciled prior-stage efficiency leads: service-sized derivation remained
|
||||
bounded; template reparsing was measured and retained; extreme profile
|
||||
counts remained a watch condition; full comparison reads became `AUD-066`;
|
||||
and production waits were separated from the test-only delays in `AUD-062`.
|
||||
- Ran a temporary local Weather API diagnostic with 25 milliseconds of
|
||||
deterministic server latency for every healthy endpoint. Five runs took
|
||||
236-240 milliseconds, issued nine serial requests, and fetched current
|
||||
conditions twice. Removed the diagnostic file immediately afterward.
|
||||
- Ran a temporary report-template benchmark five times. Parsing through the
|
||||
execution boundary took 0.283-0.291 milliseconds with about 91 KiB and 1,898
|
||||
allocations per call. Removed the benchmark file immediately afterward.
|
||||
- Ran `go test ./...`, `go vet ./...`,
|
||||
`go run ./cmd/weatherreporter --help`, and `git diff --check`; all passed.
|
||||
- Findings: `AUD-065` and `AUD-066`.
|
||||
- Retained decisions: `RET-050` through `RET-052`.
|
||||
- Open questions: the four leads recorded above are routed to their assigned
|
||||
later stages.
|
||||
|
||||
Reference in New Issue
Block a user