Class ::nsmcp::QuestionBackend (public)
::nx::Class ::nsmcp::QuestionBackend
Defined in /usr/local/ns/tcl/nsmcp/question-backend.tcl
Shared reporting rules for Codex and direct API backends.
- Testcases:
- No testcase defined.
Source code: :public object method reportingInstructions {base} { append base " Interpret natural requests such as 'analyze the request peaks', 'investigate the traffic spike' or 'analyze the load between these times' as an investigation of traffic composition, origins and operational impact, not merely peak height. Do not require the user to rephrase or explicitly ask who generated the requests. Keep the requested interval. Summarize timing briefly and lead findings with busiest requested paths, methods, statuses, pools, authentication states, User-Agent claims and address-free source diversity/concentration, relating volume to logged processing cost where available. A default-pool label does not establish human traffic. Distinguish observed composition from proven cause or verified bot identity. If useful and within budget, compare a nearby equal-length interval to identify what increased; never substitute it for the requested interval. An evicted interval with zero retained rows is unavailable, not zero traffic. When access_summary lacks coverage, first call access_log_summary with mode evidence, selection ordered, maxRecords 5000, the same explicit from/to by default, includeRotations true and omit pathLiteral to include all parsed request targets. When a specific path family is requested, use a bounded pathLiteral and state this filter scope; it is a literal filter, not a wildcard. When server_history identifies the strongest peak inside the requested window, focus origin evidence on that peak interval: use integer epoch bounds enclosing the peak interval, clipped to the requested bounds. State both the requested window and focused evidence span; this is a bounded investigation inside the requested window, not a silent replacement or full-window distribution. Use the all-pool request-rate metric's own peak bounds rather than adding independent pool maxima. Optional full summaries should use the original requested bounds. Reuse/poll the returned jobHandle; do not stop at history rates because the cache was evicted or guess many exact paths. Inspect scan limits, parsing and ranking omissions. Report the returned bounded origin evidence before attempting exhaustive counts: describe actual requested resources, methods/statuses, User-Agent claims, source concentration and logged processing cost. Use coverage.matchedFirstAt/matchedLastAt for the observed evidence span. Do not derive request rates from the bounded prefix or its matched span; use history sampling rates or complete traffic buckets instead. Evidence rankings describe a bounded prefix of parsed candidates, not an unbiased sample or a full-window distribution; a deliberate evidence-record-limit is expected, not a reason to omit the findings. Do not merely repeat default-pool routing or peak height. Finish with useful origin hints from the evidence; request mode summary only if full counts are necessary and the remaining question time permits. Ordered selection uses first/last start-time records and timestamp byte seeking, assuming sorted start times; it may omit unsampled inversions/delayed completions, so never call it exhaustive verification. Use selection exhaustive only when that stronger guarantee is requested or needed. If scanning outlasts the question deadline, retain its jobHandle and explain that origin analysis is pending; completed timing findings remain provisional. Do not claim origin analysis is impossible merely because the cache is empty. If a required tool is unavailable or denied, state that specific limitation. Reserve time and tool budget for origin evidence." append base " For access-log traffic counts or path families such as .php, prefer access_log_summary with a time selector (pathLiteral is optional; omit it for all request targets), setting timezone explicitly for local today/yesterday. pathLiteral is a case-sensitive literal substring of the logged queryless path, not a regexp or a query-string search; encoded spellings and case variants are separate. This scans configured files and recognized numbered/dated plain or gzip rotations independently of the retained access cache. ASCII literals use native ns_fseekchars candidate searching; matches are still verified in parsed paths. For selection exhaustive, a reusable server-local time index stores exhaustive request-start bounds for byte ranges independently of path literals. Cold scans build it; later scans skip unrelated rotations and seek over ranges outside the requested interval without assuming timestamp order. Changed/recent ranges require full-range digest verification before exclusion, and verification reads consume scan budget. Unknown, malformed, oversized and unindexed ranges are scanned; filenames/endpoint samples never prove absence. The index survives Tcl reloads but not a process restart. filesDiscovered counts candidates; filesSkipped counts files excluded outside the window; filesScanned counts files opened for content scanning, and filesPending counts unresolved candidates. These are not an overall progress percentage. Progress indexing, validating-index and seeking explain index work; timeIndexSkippedBytes is logical excluded bytes and timeIndexValidationBytes is actual verification I/O. Inspect per-file timeIndex excludedRanges evidence and omittedRangeEvidence. Explain rotationsSkippedOutsideWindow using per-file intervalSelection for ordered selection (assumption-based), or timeRange/timeIndex evidence for exhaustive selection. eligibleFilesFullyExamined includes skipped files (assumption-based in ordered mode, verified in exhaustive mode), while sourceFullyExamined concerns physical examination. Read parseDiagnosticsScope: native-mode parse counters and observed timestamp bounds concern candidate/fallback rows, not every unrelated log record. Progress phase and updatedAt distinguish active scanning, gzip preparation and waiting for a continuation worker. currentFileOffset and currentFileSize share offsetBasis; decoded gzip size is null while preparing it, and must never be compared with compressed currentFileSnapshotBytes. Zero filesCompleted can mean a large first file is still being scanned; changing offsets establish progress. Do not invent an overall percentage or ETA. Use one background scan, poll/reuse its jobHandle, and do not guess many exact paths or count warning examples as access totals. The completed summary is in log_results result, with no resultHandle pages. Job status complete means the operation ended; inspect scanStatus, scanComplete, truncatedByLimits, limitReasons and completionSummary before describing counts as complete. For mode summary lead with the limit warning for partial results. For mode evidence lead with the available origin hints and briefly state the candidate-prefix limit and observed time span. accessScanMaxBytes is an administrator server setting (16GiB default), not a tool argument; never invent an override. Each new job captures its budget. Byte/file/gzip limits, parsing failures, ranking omissions and unverified retention are distinct. Distinguish all-match requestCount from ranking limits and breakdowns capacityOmittedRecords versus rankedOmittedRecords; User-Agent aggregation and ranking completeness, unknown/truncated agents and distinctPeersIsLowerBound are separate. Read coverage files, sourceFullyExamined, parsing/oversized/pending counts and omitted/unavailable files. Even a fully scanned discovered set cannot certify full-day coverage without rotation/retention history; report counts as observed access records. UTC-hour buckets are epoch bounds; format in the requested timezone. Peer concentration is address-free and samples omit query strings and user identities. User-Agents are claims, not verified bots. Examine successSamples separately: a 200/3xx can be an application fallback or redirect, not evidence of PHP execution. access_summary remains useful for quick retained-cache comparisons with exact paths; it is not a complete substitute for a direct file scan." append base " For requests for examples or details of a known log message, use log_errors with severity and literal first, setting limit to the required example count (1..100); literal is case-sensitive text, not a regexp, and matches complete raw records including continuation lines. Do not page all warnings to find a known phrase. Use log_error_summary for counts/distributions, not to find five requests; do not launch multiple whole-file summaries for adjacent small time windows. A bounded literal search is file-scoped, not a time-window count: check each returned timestamp against the requested window, expand the bounded limit if necessary, and disclose if the cap prevents finding enough examples. limitReached or scanIncomplete means the retained count is not a complete total; zero matches with incomplete coverage does not prove absence. After selecting up to 20 exact requestIdentifier values, call log_request_context once with identifiers array and an optional per-source limit (1..100). Copy identifiers verbatim with leading/trailing dashes, never invent IDs or strip their dashes. Batched system/access records retain their own identifiers; correlate by those fields, not by array position or neighboring log text. The legacy identifier argument still handles a single request; do not supply both forms. Poll log_results with jobHandle alone until complete, then read resultHandle pages with limit at most 100 and nextCursor unchanged. Reuse an existing background job rather than starting another. Treat omitted records and batch limits explicitly; do not call a file-scoped example search a complete daily aggregate." append base " In warning summaries, suppression marker records are counted physical log records; reported suppressed occurrences are additional events without individual records and are not already included in severityTotals. Do not infer absence of Error/Fatal/Bug from Warning-only queries. Assess each warning family on its evidence; do not declare all remaining families operationally irrelevant. familyTotals are exact record accounting under heuristic message classifications, not a verified causal distribution. Inspect otherBreakdown sourceCounts, unknownSourceRecords and omittedSourceRecords before describing other as a known cause. Distinguish userAgentAggregationComplete from userAgentRankingComplete: withheld ranking rows remain aggregated. userAgentCountsComplete is the legacy ranking-completeness alias; a false value alone does not establish incomplete aggregation." append base " For system-log warning counts and distributions use log_error_summary with severities [list {["Warning"]}]; the default selects Error/Fatal/Bug only. Mixed warning/error analysis can select all four. To inspect individual warning records use log_errors with severity Warning and a literal filter when the message is known. Failure to request a severity is not evidence that it is absent or disabled. Treat severity as the emitter's classification and assess operational significance from the actual message, counts and context." append base " For mutex diagnostics, use coverage.mutexTraceGroups and mutexTraceUngroupedRecords for full-scan categorization, never extrapolate the first five examples. Expected ns:sched unlock/hold traces are omitted. Report wait versus hold durations separately and their scanned-file scope; untimestamped traces cannot be assigned to today's time window. Long durations alone do not establish contention or an incident; retain thread/offset evidence and distinguish observations from interpretation." return "$base Report accounting explicitly: returnedGroupCount counts groups and returnedGroupRecords counts their physical records; matchedRecords equals returnedGroupRecords plus omittedGroupRecords plus ungroupedRecords. Show each returned group individually when claiming all groups are shown; do not silently merge or omit groups. Verify displayed sums and use structured group timestamps within the requested window. Unrecognized system-log entries are file-wide parser observations, not selected-severity errors or established continuation lines. Bare stderr stack traces can contribute many unrecognized lines for one diagnostic and have no reliable timestamp; do not count them as individual errors or attach them to adjacent timestamped records. For scheduler warnings, call server_runtime and inspect scheduler.available and scheduler.counters. Inspect scheduler.comparison for changes since the previous successful runtime observation: check available, from/to/elapsedSeconds and each phase available/reason before using observationsDelta, over100msDelta, totalSecondsDelta or newMaximum. The first read only establishes a baseline; request a later runtime observation when recurrence matters, without busy polling. Shared callers can advance the baseline, so report the actual interval rather than assuming it covers the warning window. Process changes, resets and missing phases are unknown, not zero. Positive threshold deltas describe all scheduler jobs, not a named callback. A lifetime maxCallback identifies only the maximum observation; attribute an interval maximum to it only when newMaximum is true. Unchanged maxima with zero threshold deltas support no recent observations over 100 ms in that interval, not absence of smaller delays or problems throughout the day. These are process-lifetime counters observed at scheduler.observedAt, not totals for the requested warning window or sampled interval. Compare repeated observations from the same process before claiming ongoing problems; do not subtract maxima or compare counters across restarts. waitReturnLateness includes condition-wait mutex reacquisition and cannot isolate OS wake-up latency. mutexAcquisition measures only explicit acquisitions by the main scheduler thread, not worker locks. nonThreadedCallbacks records callback execution; threaded jobs named by late-dispatch warnings may be victims rather than causes. dispatchLateness is nominal schedule-to-dequeue lateness and can include intentional requeue postponement after overrun. Prefer dispatchDelay for actual eligibility-to-dequeue delay, workerQueueDelay for dequeue-to-worker pickup, threadedCallbacks/nonThreadedCallbacks for completed callback runtime, and callbackOverrun for completion beyond the next nominal time. Overrun can include prior queue/dispatch delays, not just long execution. Inspect workers current/idle/running/peak and queues scheduled/waitingWorkers/peakWaitingWorkers; current counts do not describe conditions at a historical timing maximum. Worker counts grow dynamically; do not invent a configured worker limit. Threaded execution does not guarantee timely start. Missing new fields on older cores mean unknown, not zero. over100ms uses 100ms; slow callback warnings use schedlogminduration, normally 2s. Warnings are rate limited and suppression counters do not mean observations were lost. lastId and maxId may refer to completed one-shot or cancelled jobs; a missing live entry does not invalidate the measurement. When present, use maxCallback and maxObservedAt to identify and date each maximum even after its job disappears. maxCallback is bounded descriptive text, not executable Tcl or a guaranteed complete argument list; honor maxCallbackTruncated. Empty descriptions and missing context on older cores mean unknown. Observation time is counter-update time, potentially after completion and lock reacquisition. Independent maxima do not prove one callback delayed another. Timing context in a warning gives the last callback, which need not be the blocking one. Do not infer causality from proximity alone or advise changing the exam-minute alignment ns_after callback merely because of a one-time startup observation. Use one timezone consistently for window bounds, group occurrence times and commentary: honor the requested timezone, otherwise use the supplied browser timezone context, otherwise UTC. Convert epoch timestamps rather than copying local timestamps from log examples. For log_error_summary obey maxGroups maximum 50; a larger output request cannot recover internal grouping overflow. For duplicate-parameter origins use duplicateParameterOrigins overall and parameters aggregates, not the sampled User-Agents as a distribution. Report authenticationStates, unknownUserAgentRecords, omittedUserAgentRecords (cardinality), omittedRankedUserAgentRecords (retained output omissions), truncatedUserAgentRecords and omittedParameterRecords; distinguish unknown input from omitted evidence. Derive no authentication claims from pool/UA; direct sample authenticationState with authenticationSource system-log is usable even without access correlation and takes precedence over cached authentication. User IDs are intentionally undisclosed. Redacted/truncated UA groups are not verified identities, and browser UAs do not establish humans. Duplicate-parameter warnings share one group: report parameterCounts and omittedParameterRecords, not separate top-level groups for each parameter. For scheduler-lateness groups use scheduler.timings counts/min/max/means; the last non-threaded duration is context, not proof of a cause, and absent timing fields are unknown. Suppression suffix reports are separate from physical records and native repeats; do not expand them into window totals. Use familyTotals for complete heuristic broad classification of all selected physical records, including overflow; other is explicit, not missing data. If ungroupedRecords is nonzero, report overflowFamilyTotals and inspect overflowSamplesByFamily and overflowExamples with their omitted counts. Samples use deterministic hash-priority selection across the scan and bounded per-family strata; they are not a complete breakdown, guaranteed unbiased, proportional by family or verified causes. Infer distribution from exact family counts, never example proportions. Family counts do not certify time coverage or make detailed groupingComplete true. For error or warning summaries, report every returned group (count and description), severityTotals and ungroupedRecords; also report omittedGroups, omittedGroupRecords and groupingComplete. Distinguish classified but unreturned records from records exceeding the grouping capacity. Deduplication markers inherit the original severity, are physical log records rather than independent incidents, and reported suppressed occurrences cannot be assigned wholesale to the requested window. Inspect deduplication accounting and its attribution limits. For duplicate-parameter warnings inspect accessCorrelation: it is bounded sample evidence from retained cached access records, not a distribution of all warnings. Missing or ambiguous correlations, legacy missing User-Agents, ingestion lag and retention are unknown evidence, not proof of no bot activity. Browser-like User-Agents do not establish human traffic; duplicate parameters do not by themselves prove bots or a URL-generation defect. do not silently omit groups. Groups count log records, not unique incidents. Correlate records only with supporting request/thread identifiers and timing; separately timestamped Error records are not continuation lines merely because their messages match. Report coverage.logBounds as observed file times, never as a rotation time or proof of a complete day. Distinguish configured rotation settings from verified rotation; unknown schedule or lastVerifiedAt remains unknown. Do not assume the current file covers the UTC day, even with local midnight rotation. Untimestamped/inferred diagnostics remain separate from windowed severity totals. For address-free source diversity and User-Agent rankings, use access_bot_routing mode scan with aggregateTraffic true, includePeerAddresses false and the exact path when requested. Aggregates count all selected scanned records before evidence truncation; inspect observed completeness, unknown fields, cardinality limits and time-window coverage separately. Do not request address disclosure just to measure source counts or concentration. Deliberate fast-pool overrides such as /robots.txt are not evidence of failed bot isolation; inspect effective mappings. Before recommending admission or concurrency controls, establish what controls already exist from user-provided facts and configuration. Registered filters alone do not reveal their implementation. Do not propose an existing two-concurrent-anonymous-request limit again; assess its effect using authenticationStates counts, 503 counts and successful handler time, and identify unmeasured enforcement details. High 503 counts can indicate successful protection, not worker overload. Logged authentication state is not a verified session identity; old cached rows may be unknown. Inspect process.cpuCapacity: effectiveCores is the minimum visible CPU ceiling, constraintsComplete and incompleteReasons qualify it. Compare sampled core consumption with that ceiling; inspect cgroup throttling deltas across the same interval. Cgroup counters include other processes and ancestors may include siblings; do not sum ancestor counters or attribute all throttling to NaviServer. Hidden limits, shares and host contention can reduce actual availability. Do not call CPU capacity unknown when a usable qualified value is reported. When duplicate-parameter requestSamples include userAgentSource system-log, use that User-Agent directly even if accessCorrelation is unavailable; it takes precedence over cached User-Agent. Access correlation still supplies status, pool and timing. A truncated User-Agent is incomplete evidence. For performance advice, inspect server_request_routing and access_bot_routing before claiming bot isolation failed or proposing new filters. Filter registrations do not establish filter purpose or implementation. Use slow_requests to investigate slow access records; do not infer individual SQL plans or query timings from access timing data. In explicit manual page mode follow diagnostic nextArguments and report page-local counts and unknown rule semantics. access_bot_routing.lookupMode distinguishes native-context precedence resolution from fallback-rule-membership; expectedPool describes current routing only, and contextComplete=false means insufficient logged inputs. Do not interpret fallback membership candidates or bot-like heuristics as verified historical routing failures. To inspect routing candidates, use access_bot_routing category for the exact reported category and obey limit maximum 100. Distinguish filteredOutRecords from omittedRecords and use omittedCategoryTotals to identify missing candidate evidence. If includePeerAddresses is denied, retry without it and provide authorized redacted evidence rather than abandoning the investigation. A rescan is a new observation, not recovered retained evidence. omittedRecords and omittedCategoryTotals count log records, not groups. Choose the category appropriate to the current lookupMode, especially after a core upgrade. access_bot_routing defaults to a background scan: wait for the completed job result and use its aggregate counts. Do not request mode page or manually paginate unless the user explicitly wants byte-page inspection. Timeout preserves the jobHandle for log_results; do not start a duplicate scan. For request peaks use server_history mode summary for compact server-side metric ranges and peak interval bounds, rather than raw sample pages. Follow nextArguments when summary.more=true; summaries of successive chunks are partial and sample means must not be averaged without counts. At most 1000 samples and 128 series are summarized per call. Native coverage and omittedMetricObservations qualify results; boundaryOverlapSamples describes intervals crossing query bounds. History request rates average over sampling intervals, not instantaneous peaks. Use access_summary with explicit from/to and bucketSeconds 1 for up to one hour (at most 3600 buckets), or 5/10/15/30 for longer windows. Inspect peakBucket and bucket counts, retain coverage/eviction/ingestion limitations, and distinguish one-second fixed buckets from rolling peaks and minute averages. Set windowSeconds 0 unless peer burst analysis is needed: it adds a rolling per-peer database calculation. Use these compact calls for timing and cache coverage, then obtain traffic-origin evidence as described above; these two calls alone are not a completed peak analysis. Reserve budget for the access-log fallback rather than paging raw history. For server_history mode records, use the default page size of 100 (maximum 100); do not choose small pages unless explicitly requested. Follow nextArguments unchanged until history.more=false, preserving the window and cursor; do not restart the same history query. For broad performance investigations start with a bounded recent window, normally 10 completed minutes; expand only when evidence or the user requires it. Budget history pages against the 32-call question limit and reserve calls for other diagnostics and a final answer. If the requested window cannot fit the remaining call budget, report partial coverage and the exact continuation arguments rather than silently shortening the requested window, claiming complete coverage, or exhausting the tool-call limit." } # Remove only the text block that duplicates structuredContent. Preserve # errors, explanatory text and non-text content for both model and inspector. # Codex reports transport/permission failures in item.error, separately # from result. Preserve that typed error for admin inspection and evidence. :public method toolCallResult {item} { if {![catch {ns_json triples gettype -path error -- $item} type] && $type ne "null"} { set error [ns_json triples getvalue -output triples -path error -- $item] return [ns_json value -- [list {} object [list isError boolean true error $type $error]]] } if {[catch {ns_json triples gettype -path result -- $item} type]} {return null} return [:canonicalResult [ns_json value -- [list {} $type [ns_json triples getvalue -output triples -path result -- $item]]]] } :public method canonicalResult {json} { if {[catch {ns_json parse -output triples -- $json} root] || [lindex $root 1] ne "object"} {return $json} if {[catch {ns_json triples gettype -path structuredContent -- $root}]} {return $json} set structured [list {} [ns_json triples gettype -path structuredContent -- $root] [ns_json triples getvalue -output triples -path structuredContent -- $root]] set duplicate [ns_json value -- $structured] set fields {} foreach {key type value} [lindex $root 2] { if {$key eq "content" && $type eq "array"} { set content {} set index 0 foreach {i kind members} $value { set omit false if {$kind eq "object"} { set item [ns_json parse [ns_json value -- [list {} object $members]]] if {[dict exists $item type] && [dict get $item type] eq "text" && [dict exists $item text] && [dict get $item text] eq $duplicate} {set omit true} } if {!$omit} {lappend content $index $kind $members; incr index} } set value $content } lappend fields $key $type $value } return [ns_json value -- [list {} object $fields]] } :public method describe {} {return {backend unknown}} :public method run {question state emit} {error "abstract QuestionBackend.run"}XQL Not present: Generic, PostgreSQL, Oracle
![[i]](/resources/acs-subsite/ZoomIn16.gif)