Skip to main content

Operator Briefing

@webframp/operator-briefingv2026.10.14.1· Apache-2.0(was none)· 12d agoBEHAVIORSWORKFLOWSREPORTS
01README

Unified daily operator briefing report. A workflow-scope report over the daily-briefing workflow that loops the run's step executions, dispatches each step by modelType to a per-source normalizer, and flattens everything into two projections: a prioritized four-tier review queue and a set of ops signals. It renders a consistent markdown briefing plus a STABLE JSON contract that downstream renderers (a live HTML view, executive R/vellum reports) consume — observe once, render many.

Sources (today)

  • @webframp/gitlab — cross-project review queue (MRs + todos), tiered per the daily-briefing design: waiting on you / awaiting your merge / mentions / your open MRs. Dedups on reference, folds assigned∩authored into your-MRs, and drops items you have already approved.
  • @webframp/anthropic/analytics — seats (DAU/WAU/MAU), adoption, cost window. A collected: false fetch is rendered "unavailable", never as a zero.
  • @webframp/anthropic/compliance — effective-settings count and recent activity volume.
  • @webframp/aws/service-quotas — per-service quota utilization over threshold and pending increase requests, with failedProfiles degradation (including the sso-login-required re-auth hint).
  • @webframp/aws/securityhub-findings — Security Hub severity summary across the AWS Organization (CRITICAL/HIGH/MEDIUM/LOW counts, 24h window), the new/resolved finding delta since the previous run (the actionable "N new criticals" signal), and the account-ID→name map (recognized but not surfaced — account identifiers are never emitted).
  • @webframp/aws/cost-explorer — consolidated AWS cost trend (7-day window) from the payer account with direction indicator, plus period-over-period comparison (warns on a material rise and names the top service driver) and the top cost drivers by service + usage type.
  • @webframp/aws/ecr-observation — fleet-wide ECR image hygiene: ADR-011 naming violations and repos missing a lifecycle policy, warned from the aggregate rollup (per-account detail is never surfaced).
  • @webframp/aws/kiro-usage — Kiro-on-Bedrock net seat spend and active user count for the billing month (per-user rows are never surfaced), warning only on a non-zero overage.
  • @webframp/aws/logs — GitLab EKS CloudWatch error-keyword analysis, an intentionally ungraded factual signal; the severity judgment is made by the paired TypeSafe verdict, not the raw count.
  • @swamp/typesafe-ai — the TypeSafe (System One) interpretation verdicts on the security, cost-anomaly, and GitLab-logs signals, graded from each evaluation's ordered score legend and accompanied by compact factual evidence. Review-queue triage uses triage_batch from @webframp/typesafe-batch: one bounded, source-scoped batch that retains answers only, never raw MR state.
  • @webframp/redmine — open issues assigned to the operator across all projects (equivalent to /my/page), surfaced as tier-1 queue items.

Adding a source is one workflow step plus one normalizer plus one registry line; the render / tiering / freshness core does not change.

Accuracy

Freshness is judged from each source's own fetchedAt (stale > 24h for ops,

7d for queue items). Unknown modelType / missing normalizer / parse failure are skipped and counted. The report degrades — it never throws.

Reports

  • @webframp/operator-briefing (workflow scope) — the full daily briefing: GitLab review queue plus ops signals, rendered after a daily-briefing workflow run completes.
  • @webframp/operator-briefing/review-queue (method scope) — a fast path that renders just the four GitLab review tiers LIVE on every list_my_merge_requests run, reusing the same normalizer and renderer so its output matches the briefing's GitLab section (no ops section).

Models

  • @webframp/operator-briefing/metrics — a durable append-only time-series accumulator. Point-in-time briefing data is re-observable, but a time series is not: once a versioned snapshot is GC'd that historical point is gone. Its append_metrics method upserts one day's metrics (spend, DAU/WAU/MAU, seats, AWS quota counts, …) by date into a single series resource whose latest version holds the entire history, so trend charts survive garbage collection. It merges fields for a shared date, never throws, and never overwrites a longer history with a shorter one.

Usage

Require the workflow report on the daily-briefing workflow; it renders after the run completes. Require the method report on the @webframp/gitlab model's list_my_merge_requests method for a live queue between briefings. Read the results with:

swamp data get report-@webframp/operator-briefing --markdown
swamp data get report-@webframp/operator-briefing-json --json
swamp data get "report-@webframp/operator-briefing/review-queue" --markdown
02Release Notes

2026.10.14.1

Added: The manifest now declares license: Apache-2.0 (SPDX). The registry quality rubric scores a declared license separately from the bundled LICENSE.md.

Upgrade note: Metadata only. No code, schema, or behavioral changes.

2026.10.06.1

Changed: The daily-briefing-typesafe workflow step triage_reviews is now triage-reviews, following the direction of swamp-club lab #3060 (kebab-case step names). Anything that references the step by name, such as steps.triage_reviews expressions or workflow resume --from triage_reviews, must use the new name.

Upgrade note: The briefing report does not look this step up by name, so stored data and report output are unaffected and no migration is needed.

2026.09.26.1

Changed: triage_batch moved to its own package, @webframp/typesafe-batch 2026.09.26.1, which this package now depends on. Pulling this version installs it, so @webframp/daily-briefing-typesafe and stored triage-batch-* resources work as before. The method is unchanged.

2026.09.25.1

Added: The briefing contract now carries jev (@swamp/typesafe-ai) enrichment on queue items as QueueItem.jev — advisory and additive. Base per-item triage-* answers are joined onto the matching queue item by reference: MR review recommendation (approve / comment / request_changes), Renovate bumpRisk, and Redmine issue assessment (issueType, sourceDomain, describesVulnerability). A described improper-access mechanism (describesVulnerability noul >= 0.5) also emits an explicit issue-vulnerability ops signal (critical >= 0.75, else warn) so the contract itself flags it. The markdown queue table gains a jev column, shown only for tiers with enrichment and only for choices at confidence >= 0.5.

Changed: The @swamp/typesafe-ai normalizer now collects per-item triage-* answers for this advisory attachment instead of discarding them; it still emits no queue/ops noise for ordinary triage answers.

Fixed: A workflow step the engine SKIPPED (its guard fired — e.g. jev triage guarded off an empty queue) no longer counts as a source failure or marks the contract degraded. This surfaced when the briefing split into a cheap read-only workflow whose jev grade/assessment steps routinely skip on an empty queue or no held-back Renovate MRs.

Note: jev enrichment is strictly advisory. It NEVER reorders or re-tiers the queue — deterministic tiering and the existing verified-batch ordering are unchanged (operator decision, 2026-09-25). The JSON contract is additive: no field was removed, and all jev fields are optional, so existing consumers keep working and opt in when ready. Raw low-confidence answers remain in the JSON; only the markdown suppresses labels below 0.5 confidence.

2026.09.24.2

Fixed: The packaged TypeSafe briefing workflow now preserves the CEL projection for triage_batch as an array-valued input. Previously YAML's folded scalar form coerced the projection to a string, so queue collection succeeded but TypeSafe triage failed input validation.

2026.09.24.1

Added: triage_batch, an extension method on @swamp/typesafe-ai for bounded, per-queue TypeSafe evaluation, plus the packaged @webframp/daily-briefing-typesafe workflow. A batch stores answers and partial-failure status only—never raw item state or question text.

Fixed: TypeSafe briefing verdicts now include compact factual evidence from their projected source state. Security evidence uses the Security Hub account map to render friendly names only; an unmapped account ID is never shown. A failed TypeSafe ask step now emits a degraded interpretation signal instead of being mistaken for a clean verdict; expected skipped triage does not.

Changed: Each batch carries a deterministic SHA-256 sourceFingerprint of its compact queue. Consumers must verify it before use; on a mismatch or a partial batch failure, use deterministic queue ordering rather than an old or incomplete AI classification.

Upgrade note: Pull @swamp/typesafe-ai@2026.09.15.1 and @webframp/gitlab@2026.09.23.1 with this release. Existing per-item triage-* resources remain readable; migrate consumers to triage_batch.

03Behaviors1
@webframp/operator-briefing/metricsv2026.10.14.1metrics/metrics.ts
fn append_metrics(date: string, spendUsd?: number, dau?: number, wau?: number, mau?: number, activeSeats?: number, totalSeats?: number, projects?: number, skills?: number, connectors?: number, quotaOverCount?: number, pendingCount?: number, redmineIssueCount?: number, criticalFindingCount?: number, highFindingCount?: number, awsCostTotal7d?: number, backfill?: array)
Append (upsert-by-date, merging fields) one day's metrics onto the durable series. Accepts an optional `backfill` array to seed prior dates once. Reads the latest series, merges, sorts ascending by date, and writes the whole series back under the stable name 'metrics'. Never throws, and never clobbers: if the prior series can't be read or is malformed, it skips the write rather than overwrite history with a shorter series.
ArgumentTypeDescription
datestringThe row date in zero-padded YYYY-MM-DD form (required).
spendUsd?numberSpend in USD for the day.
dau?numberDaily active users.
wau?numberWeekly active users.
mau?numberMonthly active users.
activeSeats?numberActive seats.
totalSeats?numberTotal provisioned seats.
projects?numberProject count.
skills?numberSkill count.
connectors?numberConnector count.
quotaOverCount?numberCount of AWS quotas over threshold.
pendingCount?numberCount of pending quota-increase requests.
redmineIssueCount?numberCount of open Redmine issues assigned to the operator.
criticalFindingCount?numberCount of CRITICAL Security Hub findings (24h window).
highFindingCount?numberCount of HIGH Security Hub findings (24h window).
awsCostTotal7d?numberTotal AWS cost (USD) for the trailing 7-day window.
backfill?arrayOptional prior rows to seed once. Applied before the current run's row; incoming values win on a shared date.
fn render_dashboard(redact?: boolean, title?: string, report?: record)
Render a self-contained HTML dashboard from the durable metrics series (trends) and, optionally, the operator-briefing report JSON (today's queue + ops). Writes a versioned `dashboard` file resource. `redact: true` produces a shareable variant that shows only aggregate counts and numeric trends — no references, authors, or free-text ops detail (never any internal URL or identifier). Reads only its own series; never fetches. Degrades rather than throws.
ArgumentTypeDescription
redact?booleanProduce a shareable, redacted dashboard: aggregate counts + numeric trends only, with every reference / author / ops detail stripped. Default false (operator-local, full detail).
title?stringDashboard title. Defaults to 'Operator Briefing'.
report?recordOptional operator-briefing report JSON (the BriefingJson contract: tiers, ops, generatedAt, degraded). When present, the dashboard adds a review-queue and ops-signals section; when absent it renders trends only.

Resources

series(infinite)— Append-only metrics time series; the latest version holds the full history of dated rows.

Files

dashboard(text/html)— Self-contained HTML dashboard rendered from the series (trends) and, optionally, the operator-briefing report JSON (today's queue + ops). A downstream projection of observed data; regenerated on demand, so a short retention is enough.
04Workflows1
@webframp/daily-briefing-typesafe76a7db87-8d50-464a-9b72-3628d33f8988

Fetch the GitLab review queue and apply bounded TypeSafe triage. The evaluation step is isolated: a provider outage leaves the factual queue and operator briefing available.

fetchFetch the factual queue, then classify its compact projection.
1.queue${{ inputs.gitlabModel }}.list_my_merge_requests— GitLab MRs and todos for the authenticated operator.
2.triage-reviews${{ inputs.typesafeModel }}.triage_batch— Classify a compact review projection in one bounded batch. Raw MR state and questions are not retained; individual failures degrade to deterministic queue ordering.
05Reports2
@webframp/operator-briefingworkflow
operator_briefing.ts

Unified daily operator briefing: GitLab review queue (four tiers) plus ops signals (analytics, compliance, AWS quotas), normalized into a consistent markdown briefing and a stable JSON contract.

briefingoperatorgitlabopsdashboard
@webframp/operator-briefing/review-queuemethod
review_queue.ts

Fast-path GitLab review queue (four tiers) rendered live on every `list_my_merge_requests` run. Reuses the daily briefing's shared normalizer and renderer so its output matches the briefing's GitLab section; emits the same stable JSON contract restricted to the queue tiers (no ops).

briefingoperatorgitlabreview-queuefast-path
06Previous Versions18
2026.10.06.1

2026.10.06.1

Changed: The daily-briefing-typesafe workflow step triage_reviews is now triage-reviews, following the direction of swamp-club lab #3060 (kebab-case step names). Anything that references the step by name, such as steps.triage_reviews expressions or workflow resume --from triage_reviews, must use the new name.

Upgrade note: The briefing report does not look this step up by name, so stored data and report output are unaffected and no migration is needed.

2026.09.26.1

Changed: triage_batch moved to its own package, @webframp/typesafe-batch 2026.09.26.1, which this package now depends on. Pulling this version installs it, so @webframp/daily-briefing-typesafe and stored triage-batch-* resources work as before. The method is unchanged.

2026.09.25.1

Added: The briefing contract now carries jev (@swamp/typesafe-ai) enrichment on queue items as QueueItem.jev — advisory and additive. Base per-item triage-* answers are joined onto the matching queue item by reference: MR review recommendation (approve / comment / request_changes), Renovate bumpRisk, and Redmine issue assessment (issueType, sourceDomain, describesVulnerability). A described improper-access mechanism (describesVulnerability noul >= 0.5) also emits an explicit issue-vulnerability ops signal (critical >= 0.75, else warn) so the contract itself flags it. The markdown queue table gains a jev column, shown only for tiers with enrichment and only for choices at confidence >= 0.5.

Changed: The @swamp/typesafe-ai normalizer now collects per-item triage-* answers for this advisory attachment instead of discarding them; it still emits no queue/ops noise for ordinary triage answers.

Fixed: A workflow step the engine SKIPPED (its guard fired — e.g. jev triage guarded off an empty queue) no longer counts as a source failure or marks the contract degraded. This surfaced when the briefing split into a cheap read-only workflow whose jev grade/assessment steps routinely skip on an empty queue or no held-back Renovate MRs.

Note: jev enrichment is strictly advisory. It NEVER reorders or re-tiers the queue — deterministic tiering and the existing verified-batch ordering are unchanged (operator decision, 2026-09-25). The JSON contract is additive: no field was removed, and all jev fields are optional, so existing consumers keep working and opt in when ready. Raw low-confidence answers remain in the JSON; only the markdown suppresses labels below 0.5 confidence.

2026.09.24.2

Fixed: The packaged TypeSafe briefing workflow now preserves the CEL projection for triage_batch as an array-valued input. Previously YAML's folded scalar form coerced the projection to a string, so queue collection succeeded but TypeSafe triage failed input validation.

2026.09.24.1

Added: triage_batch, an extension method on @swamp/typesafe-ai for bounded, per-queue TypeSafe evaluation, plus the packaged @webframp/daily-briefing-typesafe workflow. A batch stores answers and partial-failure status only—never raw item state or question text.

Fixed: TypeSafe briefing verdicts now include compact factual evidence from their projected source state. Security evidence uses the Security Hub account map to render friendly names only; an unmapped account ID is never shown. A failed TypeSafe ask step now emits a degraded interpretation signal instead of being mistaken for a clean verdict; expected skipped triage does not.

Changed: Each batch carries a deterministic SHA-256 sourceFingerprint of its compact queue. Consumers must verify it before use; on a mismatch or a partial batch failure, use deterministic queue ordering rather than an old or incomplete AI classification.

Upgrade note: Pull @swamp/typesafe-ai@2026.09.15.1 and @webframp/gitlab@2026.09.23.1 with this release. Existing per-item triage-* resources remain readable; migrate consumers to triage_batch.

2026.09.26.1

2026.09.26.1

Changed: triage_batch moved to its own package, @webframp/typesafe-batch 2026.09.26.1, which this package now depends on. Pulling this version installs it, so @webframp/daily-briefing-typesafe and stored triage-batch-* resources work as before. The method is unchanged.

2026.09.25.1

Added: The briefing contract now carries jev (@swamp/typesafe-ai) enrichment on queue items as QueueItem.jev — advisory and additive. Base per-item triage-* answers are joined onto the matching queue item by reference: MR review recommendation (approve / comment / request_changes), Renovate bumpRisk, and Redmine issue assessment (issueType, sourceDomain, describesVulnerability). A described improper-access mechanism (describesVulnerability noul >= 0.5) also emits an explicit issue-vulnerability ops signal (critical >= 0.75, else warn) so the contract itself flags it. The markdown queue table gains a jev column, shown only for tiers with enrichment and only for choices at confidence >= 0.5.

Changed: The @swamp/typesafe-ai normalizer now collects per-item triage-* answers for this advisory attachment instead of discarding them; it still emits no queue/ops noise for ordinary triage answers.

Fixed: A workflow step the engine SKIPPED (its guard fired — e.g. jev triage guarded off an empty queue) no longer counts as a source failure or marks the contract degraded. This surfaced when the briefing split into a cheap read-only workflow whose jev grade/assessment steps routinely skip on an empty queue or no held-back Renovate MRs.

Note: jev enrichment is strictly advisory. It NEVER reorders or re-tiers the queue — deterministic tiering and the existing verified-batch ordering are unchanged (operator decision, 2026-09-25). The JSON contract is additive: no field was removed, and all jev fields are optional, so existing consumers keep working and opt in when ready. Raw low-confidence answers remain in the JSON; only the markdown suppresses labels below 0.5 confidence.

2026.09.24.2

Fixed: The packaged TypeSafe briefing workflow now preserves the CEL projection for triage_batch as an array-valued input. Previously YAML's folded scalar form coerced the projection to a string, so queue collection succeeded but TypeSafe triage failed input validation.

2026.09.24.1

Added: triage_batch, an extension method on @swamp/typesafe-ai for bounded, per-queue TypeSafe evaluation, plus the packaged @webframp/daily-briefing-typesafe workflow. A batch stores answers and partial-failure status only—never raw item state or question text.

Fixed: TypeSafe briefing verdicts now include compact factual evidence from their projected source state. Security evidence uses the Security Hub account map to render friendly names only; an unmapped account ID is never shown. A failed TypeSafe ask step now emits a degraded interpretation signal instead of being mistaken for a clean verdict; expected skipped triage does not.

Changed: Each batch carries a deterministic SHA-256 sourceFingerprint of its compact queue. Consumers must verify it before use; on a mismatch or a partial batch failure, use deterministic queue ordering rather than an old or incomplete AI classification.

Upgrade note: Pull @swamp/typesafe-ai@2026.09.15.1 and @webframp/gitlab@2026.09.23.1 with this release. Existing per-item triage-* resources remain readable; migrate consumers to triage_batch.

updated dependencies

2026.09.25.1

2026.09.25.1

Added: The briefing contract now carries jev (@swamp/typesafe-ai) enrichment on queue items as QueueItem.jev — advisory and additive. Base per-item triage-* answers are joined onto the matching queue item by reference: MR review recommendation (approve / comment / request_changes), Renovate bumpRisk, and Redmine issue assessment (issueType, sourceDomain, describesVulnerability). A described improper-access mechanism (describesVulnerability noul >= 0.5) also emits an explicit issue-vulnerability ops signal (critical >= 0.75, else warn) so the contract itself flags it. The markdown queue table gains a jev column, shown only for tiers with enrichment and only for choices at confidence >= 0.5.

Changed: The @swamp/typesafe-ai normalizer now collects per-item triage-* answers for this advisory attachment instead of discarding them; it still emits no queue/ops noise for ordinary triage answers.

Fixed: A workflow step the engine SKIPPED (its guard fired — e.g. jev triage guarded off an empty queue) no longer counts as a source failure or marks the contract degraded. This surfaced when the briefing split into a cheap read-only workflow whose jev grade/assessment steps routinely skip on an empty queue or no held-back Renovate MRs.

Note: jev enrichment is strictly advisory. It NEVER reorders or re-tiers the queue — deterministic tiering and the existing verified-batch ordering are unchanged (operator decision, 2026-09-25). The JSON contract is additive: no field was removed, and all jev fields are optional, so existing consumers keep working and opt in when ready. Raw low-confidence answers remain in the JSON; only the markdown suppresses labels below 0.5 confidence.

2026.09.24.2

Fixed: The packaged TypeSafe briefing workflow now preserves the CEL projection for triage_batch as an array-valued input. Previously YAML's folded scalar form coerced the projection to a string, so queue collection succeeded but TypeSafe triage failed input validation.

2026.09.24.1

Added: triage_batch, an extension method on @swamp/typesafe-ai for bounded, per-queue TypeSafe evaluation, plus the packaged @webframp/daily-briefing-typesafe workflow. A batch stores answers and partial-failure status only—never raw item state or question text.

Fixed: TypeSafe briefing verdicts now include compact factual evidence from their projected source state. Security evidence uses the Security Hub account map to render friendly names only; an unmapped account ID is never shown. A failed TypeSafe ask step now emits a degraded interpretation signal instead of being mistaken for a clean verdict; expected skipped triage does not.

Changed: Each batch carries a deterministic SHA-256 sourceFingerprint of its compact queue. Consumers must verify it before use; on a mismatch or a partial batch failure, use deterministic queue ordering rather than an old or incomplete AI classification.

Upgrade note: Pull @swamp/typesafe-ai@2026.09.15.1 and @webframp/gitlab@2026.09.23.1 with this release. Existing per-item triage-* resources remain readable; migrate consumers to triage_batch.

2026.09.24.2

2026.09.24.2

Fixed: The packaged TypeSafe briefing workflow now preserves the CEL projection for triage_batch as an array-valued input. Previously YAML's folded scalar form coerced the projection to a string, so queue collection succeeded but TypeSafe triage failed input validation.

2026.09.24.1

Added: triage_batch, an extension method on @swamp/typesafe-ai for bounded, per-queue TypeSafe evaluation, plus the packaged @webframp/daily-briefing-typesafe workflow. A batch stores answers and partial-failure status only—never raw item state or question text.

Fixed: TypeSafe briefing verdicts now include compact factual evidence from their projected source state. Security evidence uses the Security Hub account map to render friendly names only; an unmapped account ID is never shown. A failed TypeSafe ask step now emits a degraded interpretation signal instead of being mistaken for a clean verdict; expected skipped triage does not.

Changed: Each batch carries a deterministic SHA-256 sourceFingerprint of its compact queue. Consumers must verify it before use; on a mismatch or a partial batch failure, use deterministic queue ordering rather than an old or incomplete AI classification.

Upgrade note: Pull @swamp/typesafe-ai@2026.09.15.1 and @webframp/gitlab@2026.09.23.1 with this release. Existing per-item triage-* resources remain readable; migrate consumers to triage_batch.

2026.09.24.1

2026.09.24.1

Added: triage_batch, an extension method on @swamp/typesafe-ai for bounded, per-queue TypeSafe evaluation, plus the packaged @webframp/daily-briefing-typesafe workflow. A batch stores answers and partial-failure status only—never raw item state or question text.

Fixed: TypeSafe briefing verdicts now include compact factual evidence from their projected source state. Security evidence uses the Security Hub account map to render friendly names only; an unmapped account ID is never shown. A failed TypeSafe ask step now emits a degraded interpretation signal instead of being mistaken for a clean verdict; expected skipped triage does not.

Changed: Each batch carries a deterministic SHA-256 sourceFingerprint of its compact queue. Consumers must verify it before use; on a mismatch or a partial batch failure, use deterministic queue ordering rather than an old or incomplete AI classification.

Upgrade note: Pull @swamp/typesafe-ai@2026.09.15.1 and @webframp/gitlab@2026.09.23.1 with this release. Existing per-item triage-* resources remain readable; migrate consumers to triage_batch.

Added 1 workflows. updated dependencies

2026.09.23.1

2026.09.23.1

Added: Report normalizers for the daily-briefing workflow's expanded AWS ops signals, so the new fetch steps render in the briefing instead of being skipped as unrecognized:

  • Security Hub — the diff_findings delta (new/resolved findings since the last run, escalating to critical on new CRITICAL findings) and the resolve_accounts account map (recognized but deliberately not emitted, so account identifiers never surface and it no longer trips the "no recognizable shape" note).
  • Cost Explorer — cost_comparison (period-over-period spend-delta, warns at ≥10% rise and names the top service driver) and top_cost_drivers. Both the flattened specs (costComparison / costDrivers, the current model output) and the legacy {queryType, data} envelope are handled through one shared builder, and totalDeltaPercent is finite-guarded so a bad value never renders "NaN%" or trips the warn threshold.
  • ECR (@webframp/aws/ecr-observation) — fleet image-hygiene signal from the survey aggregate (ADR-011 naming violations, repos without a lifecycle policy); per-account detail is never surfaced.
  • Kiro usage (@webframp/aws/kiro-usage) — net Bedrock seat spend and user count for the billing month; warns on overage; per-user rows redacted.
  • GitLab logs (@webframp/aws/logs) — an intentionally ungraded factual error-keyword signal (the severity call is made by the TypeSafe verdict, not the raw count, since the EKS clusters emit high-volume audit noise).
  • TypeSafe verdicts (@swamp/typesafe-ai) — the interpretation ask evaluations on the security, cost, and logs signals, graded from each evaluation's ordered score legend. Per-MR triage resources from the same model are recognized and skipped (they feed the queue ordering, not ops).

Changed: The Security Hub normalizer now tracks recognized-but-unemitted shapes separately from emitted signals, so a step that produced only an account map is not falsely flagged degraded.

Upgrade note: No schema, method, or resource change. Report source changes are shipped-file changes, so the version bumps and a no-op upgrade-chain entry is appended for the metrics model.

(all permissions). The unit tests need no filesystem, network, or subprocess access — they exercise pure report/model logic through the swamp-testing factories — so the blanket grant was unnecessary. This matches the scoped permission convention used by every other model/report extension in the repo.

Upgrade note: No schema, method, or resource change. A deno.json change is a shipped-file change, so the version bumps and a no-op upgrade-chain entry is appended for the metrics model.

2026.09.18.1

2026.09.18.1

Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the repo. No behavioral changes in this extension.

2026.09.15.1

2026.09.15.1

Changed: Bump zod 4.4.3 → 4.6.5

2026.08.28.1

Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.

Upgrade note: License text only. No API, schema, or runtime behavior changed.

2026.08.26.3

Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry quality scorer can resolve dependencies and score the extension. An earlier release used a bare "zod" import-map specifier, which published but scored as unscored.

Changed: Retained explicit compilerOptions.strict in deno.json. No behavioral or schema changes.

2026.08.28.1

2026.08.28.1

Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.

Upgrade note: License text only. No API, schema, or runtime behavior changed.

2026.08.26.3

Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry quality scorer can resolve dependencies and score the extension. An earlier release used a bare "zod" import-map specifier, which published but scored as unscored.

Changed: Retained explicit compilerOptions.strict in deno.json. No behavioral or schema changes.

2026.08.26.3

2026.08.26.3

Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry quality scorer can resolve dependencies and score the extension. An earlier release used a bare "zod" import-map specifier, which published but scored as unscored.

Changed: Retained explicit compilerOptions.strict in deno.json. No behavioral or schema changes.

2026.08.26.1

2026.08.26.1

Fixed: Added missing description field to upgrade entry for version 2026.08.24.2. The omission caused swamp extension pull to fail with a catalog validation error ("upgrades.N.description: Invalid input: expected string, received undefined").

2026.08.24.3

2026.08.24.3

Added: Output metadata attributes for observability.

  • durationMs: Method execution duration in milliseconds.
  • collectedBy: Extension name that produced the data.
  • fetchedAt: ISO 8601 timestamp when data was fetched (added to resources that previously lacked it).
2026.08.24.2

2026.08.24.2

Added Troubleshooting section documenting per-source degradation, append_metrics skip-write safety, dashboard empty-trend rendering, incomplete README sources table, and implicit configuration model.

2026.08.21.1

2026.08.21.1

Changed: Added .describe() to every field on the metrics model's Row and Series resource schemas, mirroring the descriptions that already existed on the corresponding append_metrics method arguments. No behavioral change.

2026.08.10.1

Added: Three new briefing sources and four new metrics fields.

Sources:

  • @webframp/aws/securityhub-findings — Security Hub severity summary (CRITICAL/HIGH/MEDIUM/LOW counts) as an ops signal.
  • @webframp/aws/cost-explorer — consolidated AWS cost trend (7-day total + direction) as an ops signal.
  • @webframp/redmine — open issues assigned to the operator across all projects, surfaced as tier-1 queue items plus an ops signal with the total count.

Metrics (append_metrics schema):

  • redmineIssueCount — open Redmine issues assigned to the operator.
  • criticalFindingCount — CRITICAL Security Hub findings (24h).
  • highFindingCount — HIGH Security Hub findings (24h).
  • awsCostTotal7d — total AWS cost (USD) for the trailing 7-day window.

All new fields are optional and merge non-destructively with existing rows. Existing model instances upgrade via identity function (no data migration).

2026.07.18.2

Added: An upgrades array entry (no-op) to metrics.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.

2026.07.18.1

Changed: Pinned the zod import specifier in the metrics model to npm:zod@4.4.3 (was npm:zod@^4.3.6) for hermetic dependency resolution. No runtime behavior change.

2026.07.13.5

Fixed: The daily briefing falsely reported degraded: true whenever the metrics_append step ran in the daily-briefing workflow.

The workflow-scope report loops every step execution and dispatches by modelType. The durable metrics accumulator (@webframp/operator-briefing/metrics) runs as a step but is not a briefing source — it has no normalizer by design — so it was skipped-and-counted like an unknown source, which set sourceErrors.skippedSteps and flipped the whole briefing to degraded: true with a spurious "No normalizer …" note.

The report now recognizes a set of non-source model types (nonSourceModelTypes in the normalizer registry; today just the metrics accumulator) and skips them silently — no skipped-source count, no note, no degraded flag. A missing normalizer for any other modelType is still a real gap and is skipped-and-counted as before.

2026.07.13.4

Added a dashboard renderer to the metrics model — the metrics series (and, optionally, the daily briefing) becomes a self-contained HTML page. Observe once, render many.

  • New render_dashboard method (@webframp/operator-briefing/metrics). Reads the model's own append-only series (trend history) and takes an optional report argument — the operator-briefing JSON contract (review queue + ops signals), wired in by the workflow; it is never cross-read from storage. Renders ONE self-contained HTML document — inline SVG sparklines, stat tiles, tier counts, and an ops table, theme-aware, with no external JS/CDN (CSP-safe; renders in a browser or a claude.ai Artifact). Reads only its own data, never fetches, and degrades rather than throwing (empty series → trends-empty page; a malformed or null-bearing report is filtered, not fatal).
  • New dashboard file resource (text/html, lifetime 30d, garbageCollection 10). A regenerated downstream projection, so short retention is right. Written via createFileWriter().writeText().
  • redact: true shareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, ops detail, and degradedReason is stripped, so no internal URL, username, or account name reaches the page (CLAUDE.md forbids exposing internal identifiers). The default (redact: false) is the operator-local full-detail view.

Additive: append_metrics, the series resource, and the existing reports and JSON contract are all unchanged.

2026.07.13.3

Added a durable time-series accumulator — the package's first model — so trends (spend, DAU burndown, adoption growth) survive version garbage collection.

  • New metrics model (@webframp/operator-briefing/metrics). Point-in-time briefing data is always re-observable, so GC-ing its snapshots is harmless. A time series is not: once a versioned snapshot is GC'd, that historical point is gone forever. So the series is stored as first-class data in a single append-only series resource whose LATEST version holds the entire history (an array of dated rows). Version-GC then only drops old partial states; the latest always has everything, so keeping a handful of versions is safe.
  • append_metrics method. Upserts one day's metrics onto the series by date. It reads the latest series, MERGES fields for a shared date (a run that carries on
2026.08.13.1

2026.08.10.1

Added: Three new briefing sources and four new metrics fields.

Sources:

  • @webframp/aws/securityhub-findings — Security Hub severity summary (CRITICAL/HIGH/MEDIUM/LOW counts) as an ops signal.
  • @webframp/aws/cost-explorer — consolidated AWS cost trend (7-day total + direction) as an ops signal.
  • @webframp/redmine — open issues assigned to the operator across all projects, surfaced as tier-1 queue items plus an ops signal with the total count.

Metrics (append_metrics schema):

  • redmineIssueCount — open Redmine issues assigned to the operator.
  • criticalFindingCount — CRITICAL Security Hub findings (24h).
  • highFindingCount — HIGH Security Hub findings (24h).
  • awsCostTotal7d — total AWS cost (USD) for the trailing 7-day window.

All new fields are optional and merge non-destructively with existing rows. Existing model instances upgrade via identity function (no data migration).

2026.07.18.2

Added: An upgrades array entry (no-op) to metrics.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.

2026.07.18.1

Changed: Pinned the zod import specifier in the metrics model to npm:zod@4.4.3 (was npm:zod@^4.3.6) for hermetic dependency resolution. No runtime behavior change.

2026.07.13.5

Fixed: The daily briefing falsely reported degraded: true whenever the metrics_append step ran in the daily-briefing workflow.

The workflow-scope report loops every step execution and dispatches by modelType. The durable metrics accumulator (@webframp/operator-briefing/metrics) runs as a step but is not a briefing source — it has no normalizer by design — so it was skipped-and-counted like an unknown source, which set sourceErrors.skippedSteps and flipped the whole briefing to degraded: true with a spurious "No normalizer …" note.

The report now recognizes a set of non-source model types (nonSourceModelTypes in the normalizer registry; today just the metrics accumulator) and skips them silently — no skipped-source count, no note, no degraded flag. A missing normalizer for any other modelType is still a real gap and is skipped-and-counted as before.

2026.07.13.4

Added a dashboard renderer to the metrics model — the metrics series (and, optionally, the daily briefing) becomes a self-contained HTML page. Observe once, render many.

  • New render_dashboard method (@webframp/operator-briefing/metrics). Reads the model's own append-only series (trend history) and takes an optional report argument — the operator-briefing JSON contract (review queue + ops signals), wired in by the workflow; it is never cross-read from storage. Renders ONE self-contained HTML document — inline SVG sparklines, stat tiles, tier counts, and an ops table, theme-aware, with no external JS/CDN (CSP-safe; renders in a browser or a claude.ai Artifact). Reads only its own data, never fetches, and degrades rather than throwing (empty series → trends-empty page; a malformed or null-bearing report is filtered, not fatal).
  • New dashboard file resource (text/html, lifetime 30d, garbageCollection 10). A regenerated downstream projection, so short retention is right. Written via createFileWriter().writeText().
  • redact: true shareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, ops detail, and degradedReason is stripped, so no internal URL, username, or account name reaches the page (CLAUDE.md forbids exposing internal identifiers). The default (redact: false) is the operator-local full-detail view.

Additive: append_metrics, the series resource, and the existing reports and JSON contract are all unchanged.

2026.07.13.3

Added a durable time-series accumulator — the package's first model — so trends (spend, DAU burndown, adoption growth) survive version garbage collection.

  • New metrics model (@webframp/operator-briefing/metrics). Point-in-time briefing data is always re-observable, so GC-ing its snapshots is harmless. A time series is not: once a versioned snapshot is GC'd, that historical point is gone forever. So the series is stored as first-class data in a single append-only series resource whose LATEST version holds the entire history (an array of dated rows). Version-GC then only drops old partial states; the latest always has everything, so keeping a handful of versions is safe.
  • append_metrics method. Upserts one day's metrics onto the series by date. It reads the latest series, MERGES fields for a shared date (a run that carries only spend never wipes that day's dau), sorts ascending by date, and writes the whole series back under the stable name "metrics" so it versions in place. A one-time backfill array seeds prior dates (incoming wins on a shared date, still field-me
2026.08.10.1

2026.08.10.1

Added: Three new briefing sources and four new metrics fields.

Sources:

  • @webframp/aws/securityhub-findings — Security Hub severity summary (CRITICAL/HIGH/MEDIUM/LOW counts) as an ops signal.
  • @webframp/aws/cost-explorer — consolidated AWS cost trend (7-day total + direction) as an ops signal.
  • @webframp/redmine — open issues assigned to the operator across all projects, surfaced as tier-1 queue items plus an ops signal with the total count.

Metrics (append_metrics schema):

  • redmineIssueCount — open Redmine issues assigned to the operator.
  • criticalFindingCount — CRITICAL Security Hub findings (24h).
  • highFindingCount — HIGH Security Hub findings (24h).
  • awsCostTotal7d — total AWS cost (USD) for the trailing 7-day window.

All new fields are optional and merge non-destructively with existing rows. Existing model instances upgrade via identity function (no data migration).

2026.07.18.2

Added: An upgrades array entry (no-op) to metrics.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.

2026.07.18.1

Changed: Pinned the zod import specifier in the metrics model to npm:zod@4.4.3 (was npm:zod@^4.3.6) for hermetic dependency resolution. No runtime behavior change.

2026.07.13.5

Fixed: The daily briefing falsely reported degraded: true whenever the metrics_append step ran in the daily-briefing workflow.

The workflow-scope report loops every step execution and dispatches by modelType. The durable metrics accumulator (@webframp/operator-briefing/metrics) runs as a step but is not a briefing source — it has no normalizer by design — so it was skipped-and-counted like an unknown source, which set sourceErrors.skippedSteps and flipped the whole briefing to degraded: true with a spurious "No normalizer …" note.

The report now recognizes a set of non-source model types (nonSourceModelTypes in the normalizer registry; today just the metrics accumulator) and skips them silently — no skipped-source count, no note, no degraded flag. A missing normalizer for any other modelType is still a real gap and is skipped-and-counted as before.

2026.07.13.4

Added a dashboard renderer to the metrics model — the metrics series (and, optionally, the daily briefing) becomes a self-contained HTML page. Observe once, render many.

  • New render_dashboard method (@webframp/operator-briefing/metrics). Reads the model's own append-only series (trend history) and takes an optional report argument — the operator-briefing JSON contract (review queue + ops signals), wired in by the workflow; it is never cross-read from storage. Renders ONE self-contained HTML document — inline SVG sparklines, stat tiles, tier counts, and an ops table, theme-aware, with no external JS/CDN (CSP-safe; renders in a browser or a claude.ai Artifact). Reads only its own data, never fetches, and degrades rather than throwing (empty series → trends-empty page; a malformed or null-bearing report is filtered, not fatal).
  • New dashboard file resource (text/html, lifetime 30d, garbageCollection 10). A regenerated downstream projection, so short retention is right. Written via createFileWriter().writeText().
  • redact: true shareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, ops detail, and degradedReason is stripped, so no internal URL, username, or account name reaches the page (CLAUDE.md forbids exposing internal identifiers). The default (redact: false) is the operator-local full-detail view.

Additive: append_metrics, the series resource, and the existing reports and JSON contract are all unchanged.

2026.07.13.3

Added a durable time-series accumulator — the package's first model — so trends (spend, DAU burndown, adoption growth) survive version garbage collection.

  • New metrics model (@webframp/operator-briefing/metrics). Point-in-time briefing data is always re-observable, so GC-ing its snapshots is harmless. A time series is not: once a versioned snapshot is GC'd, that historical point is gone forever. So the series is stored as first-class data in a single append-only series resource whose LATEST version holds the entire history (an array of dated rows). Version-GC then only drops old partial states; the latest always has everything, so keeping a handful of versions is safe.
  • append_metrics method. Upserts one day's metrics onto the series by date. It reads the latest series, MERGES fields for a shared date (a run that carries only spend never wipes that day's dau), sorts ascending by date, and writes the whole series back under the stable name "metrics" so it versions in place. A one-time backfill array seeds prior dates (incoming wins on a shared date, still field-me
2026.07.18.2

2026.07.18.2

Added: An upgrades array entry (no-op) to metrics.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.

2026.07.18.1

Changed: Pinned the zod import specifier in the metrics model to npm:zod@4.4.3 (was npm:zod@^4.3.6) for hermetic dependency resolution. No runtime behavior change.

2026.07.13.5

Fixed: The daily briefing falsely reported degraded: true whenever the metrics_append step ran in the daily-briefing workflow.

The workflow-scope report loops every step execution and dispatches by modelType. The durable metrics accumulator (@webframp/operator-briefing/metrics) runs as a step but is not a briefing source — it has no normalizer by design — so it was skipped-and-counted like an unknown source, which set sourceErrors.skippedSteps and flipped the whole briefing to degraded: true with a spurious "No normalizer …" note.

The report now recognizes a set of non-source model types (nonSourceModelTypes in the normalizer registry; today just the metrics accumulator) and skips them silently — no skipped-source count, no note, no degraded flag. A missing normalizer for any other modelType is still a real gap and is skipped-and-counted as before.

2026.07.13.4

Added a dashboard renderer to the metrics model — the metrics series (and, optionally, the daily briefing) becomes a self-contained HTML page. Observe once, render many.

  • New render_dashboard method (@webframp/operator-briefing/metrics). Reads the model's own append-only series (trend history) and takes an optional report argument — the operator-briefing JSON contract (review queue + ops signals), wired in by the workflow; it is never cross-read from storage. Renders ONE self-contained HTML document — inline SVG sparklines, stat tiles, tier counts, and an ops table, theme-aware, with no external JS/CDN (CSP-safe; renders in a browser or a claude.ai Artifact). Reads only its own data, never fetches, and degrades rather than throwing (empty series → trends-empty page; a malformed or null-bearing report is filtered, not fatal).
  • New dashboard file resource (text/html, lifetime 30d, garbageCollection 10). A regenerated downstream projection, so short retention is right. Written via createFileWriter().writeText().
  • redact: true shareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, ops detail, and degradedReason is stripped, so no internal URL, username, or account name reaches the page (CLAUDE.md forbids exposing internal identifiers). The default (redact: false) is the operator-local full-detail view.

Additive: append_metrics, the series resource, and the existing reports and JSON contract are all unchanged.

2026.07.13.3

Added a durable time-series accumulator — the package's first model — so trends (spend, DAU burndown, adoption growth) survive version garbage collection.

  • New metrics model (@webframp/operator-briefing/metrics). Point-in-time briefing data is always re-observable, so GC-ing its snapshots is harmless. A time series is not: once a versioned snapshot is GC'd, that historical point is gone forever. So the series is stored as first-class data in a single append-only series resource whose LATEST version holds the entire history (an array of dated rows). Version-GC then only drops old partial states; the latest always has everything, so keeping a handful of versions is safe.
  • append_metrics method. Upserts one day's metrics onto the series by date. It reads the latest series, MERGES fields for a shared date (a run that carries only spend never wipes that day's dau), sorts ascending by date, and writes the whole series back under the stable name "metrics" so it versions in place. A one-time backfill array seeds prior dates (incoming wins on a shared date, still field-merged).
  • Never throws, and never clobbers. The cardinal rule of an append-only accumulator is that a shorter series must never overwrite a longer one. So a write happens only when the prior history is KNOWN: a genuinely absent (null) series is treated as empty and written fresh, but a prior series that can't be READ (a thrown read — transient I/O, not proof of absence) or is MALFORMED (rows not an array, or a non-empty array with zero parseable rows) SKIPS the write rather than truncate real history. A degrade AFTER the read — a failing writeResource as the payload grows, a throwing logger — likewise leaves the stored series untouched (no fallback empty write). A wrong-shaped or non-finite metric is skipped rather than fatal, and a metric value of 0 is preserved as real data (0 is a number, not "absent"). Dates are validated as zero-padded YYYY-MM-DD, which also guarantees the lexicographic
2026.07.18.1

2026.07.18.1

Changed: Pinned the zod import specifier in the metrics model to npm:zod@4.4.3 (was npm:zod@^4.3.6) for hermetic dependency resolution. No runtime behavior change.

2026.07.13.5

Fixed: The daily briefing falsely reported degraded: true whenever the metrics_append step ran in the daily-briefing workflow.

The workflow-scope report loops every step execution and dispatches by modelType. The durable metrics accumulator (@webframp/operator-briefing/metrics) runs as a step but is not a briefing source — it has no normalizer by design — so it was skipped-and-counted like an unknown source, which set sourceErrors.skippedSteps and flipped the whole briefing to degraded: true with a spurious "No normalizer …" note.

The report now recognizes a set of non-source model types (nonSourceModelTypes in the normalizer registry; today just the metrics accumulator) and skips them silently — no skipped-source count, no note, no degraded flag. A missing normalizer for any other modelType is still a real gap and is skipped-and-counted as before.

2026.07.13.4

Added a dashboard renderer to the metrics model — the metrics series (and, optionally, the daily briefing) becomes a self-contained HTML page. Observe once, render many.

  • New render_dashboard method (@webframp/operator-briefing/metrics). Reads the model's own append-only series (trend history) and takes an optional report argument — the operator-briefing JSON contract (review queue + ops signals), wired in by the workflow; it is never cross-read from storage. Renders ONE self-contained HTML document — inline SVG sparklines, stat tiles, tier counts, and an ops table, theme-aware, with no external JS/CDN (CSP-safe; renders in a browser or a claude.ai Artifact). Reads only its own data, never fetches, and degrades rather than throwing (empty series → trends-empty page; a malformed or null-bearing report is filtered, not fatal).
  • New dashboard file resource (text/html, lifetime 30d, garbageCollection 10). A regenerated downstream projection, so short retention is right. Written via createFileWriter().writeText().
  • redact: true shareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, ops detail, and degradedReason is stripped, so no internal URL, username, or account name reaches the page (CLAUDE.md forbids exposing internal identifiers). The default (redact: false) is the operator-local full-detail view.

Additive: append_metrics, the series resource, and the existing reports and JSON contract are all unchanged.

2026.07.13.3

Added a durable time-series accumulator — the package's first model — so trends (spend, DAU burndown, adoption growth) survive version garbage collection.

  • New metrics model (@webframp/operator-briefing/metrics). Point-in-time briefing data is always re-observable, so GC-ing its snapshots is harmless. A time series is not: once a versioned snapshot is GC'd, that historical point is gone forever. So the series is stored as first-class data in a single append-only series resource whose LATEST version holds the entire history (an array of dated rows). Version-GC then only drops old partial states; the latest always has everything, so keeping a handful of versions is safe.
  • append_metrics method. Upserts one day's metrics onto the series by date. It reads the latest series, MERGES fields for a shared date (a run that carries only spend never wipes that day's dau), sorts ascending by date, and writes the whole series back under the stable name "metrics" so it versions in place. A one-time backfill array seeds prior dates (incoming wins on a shared date, still field-merged).
  • Never throws, and never clobbers. The cardinal rule of an append-only accumulator is that a shorter series must never overwrite a longer one. So a write happens only when the prior history is KNOWN: a genuinely absent (null) series is treated as empty and written fresh, but a prior series that can't be READ (a thrown read — transient I/O, not proof of absence) or is MALFORMED (rows not an array, or a non-empty array with zero parseable rows) SKIPS the write rather than truncate real history. A degrade AFTER the read — a failing writeResource as the payload grows, a throwing logger — likewise leaves the stored series untouched (no fallback empty write). A wrong-shaped or non-finite metric is skipped rather than fatal, and a metric value of 0 is preserved as real data (0 is a number, not "absent"). Dates are validated as zero-padded YYYY-MM-DD, which also guarantees the lexicographic sort is chronological.

Additive: the existing reports and the stable JSON contract are unchanged.

2026.07.13.2

**Enriched the stable JSON contract so downstrea

07Stats
A
100 / 100
Downloads
50
Archive size
74.5 KB
  • Has README or module doc2/2earned
  • README has a code example1/1earned
  • README is substantive1/1earned
  • Most symbols documented1/1earned
  • No slow types (deprecated)1/1earned
  • Dependencies pass trust audit2/2earned
  • Has description1/1earned
  • Platform support declared (or universal)2/2earned
  • License2/2earned
  • Verified public repository2/2earned
08Platforms
09Labels