Operator Briefing
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 onreference, folds assigned∩authored into your-MRs, and drops items you have already approved.@webframp/anthropic/analytics— seats (DAU/WAU/MAU), adoption, cost window. Acollected: falsefetch 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, withfailedProfilesdegradation (including thesso-login-requiredre-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 usestriage_batchfrom@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 adaily-briefingworkflow run completes.@webframp/operator-briefing/review-queue(method scope) — a fast path that renders just the four GitLab review tiers LIVE on everylist_my_merge_requestsrun, 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. Itsappend_metricsmethod upserts one day's metrics (spend, DAU/WAU/MAU, seats, AWS quota counts, …) by date into a singleseriesresource 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" --markdown2026.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.
| Argument | Type | Description |
|---|---|---|
| date | string | The row date in zero-padded YYYY-MM-DD form (required). |
| spendUsd? | number | Spend in USD for the day. |
| dau? | number | Daily active users. |
| wau? | number | Weekly active users. |
| mau? | number | Monthly active users. |
| activeSeats? | number | Active seats. |
| totalSeats? | number | Total provisioned seats. |
| projects? | number | Project count. |
| skills? | number | Skill count. |
| connectors? | number | Connector count. |
| quotaOverCount? | number | Count of AWS quotas over threshold. |
| pendingCount? | number | Count of pending quota-increase requests. |
| redmineIssueCount? | number | Count of open Redmine issues assigned to the operator. |
| criticalFindingCount? | number | Count of CRITICAL Security Hub findings (24h window). |
| highFindingCount? | number | Count of HIGH Security Hub findings (24h window). |
| awsCostTotal7d? | number | Total AWS cost (USD) for the trailing 7-day window. |
| backfill? | array | Optional prior rows to seed once. Applied before the current run's row; incoming values win on a shared date. |
| Argument | Type | Description |
|---|---|---|
| redact? | boolean | Produce a shareable, redacted dashboard: aggregate counts + numeric trends only, with every reference / author / ops detail stripped. Default false (operator-local, full detail). |
| title? | string | Dashboard title. Defaults to 'Operator Briefing'. |
| report? | record | Optional 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
Files
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.
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.
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).
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
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
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
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
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
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_findingsdelta (new/resolved findings since the last run, escalating tocriticalon new CRITICAL findings) and theresolve_accountsaccount 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-periodspend-delta, warns at ≥10% rise and names the top service driver) andtop_cost_drivers. Both the flattened specs (costComparison/costDrivers, the current model output) and the legacy{queryType, data}envelope are handled through one shared builder, andtotalDeltaPercentis 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 interpretationaskevaluations 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
Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the
repo. No behavioral changes in this extension.
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
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
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
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
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
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
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_dashboardmethod (@webframp/operator-briefing/metrics). Reads the model's own append-onlyseries(trend history) and takes an optionalreportargument — 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 ornull-bearing report is filtered, not fatal). - New
dashboardfile resource (text/html, lifetime30d,garbageCollection10). A regenerated downstream projection, so short retention is right. Written viacreateFileWriter().writeText(). redact: trueshareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, opsdetail, anddegradedReasonis 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
metricsmodel (@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-onlyseriesresource 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_metricsmethod. 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.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_dashboardmethod (@webframp/operator-briefing/metrics). Reads the model's own append-onlyseries(trend history) and takes an optionalreportargument — 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 ornull-bearing report is filtered, not fatal). - New
dashboardfile resource (text/html, lifetime30d,garbageCollection10). A regenerated downstream projection, so short retention is right. Written viacreateFileWriter().writeText(). redact: trueshareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, opsdetail, anddegradedReasonis 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
metricsmodel (@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-onlyseriesresource 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_metricsmethod. 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-timebackfillarray seeds prior dates (incoming wins on a shared date, still field-me
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_dashboardmethod (@webframp/operator-briefing/metrics). Reads the model's own append-onlyseries(trend history) and takes an optionalreportargument — 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 ornull-bearing report is filtered, not fatal). - New
dashboardfile resource (text/html, lifetime30d,garbageCollection10). A regenerated downstream projection, so short retention is right. Written viacreateFileWriter().writeText(). redact: trueshareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, opsdetail, anddegradedReasonis 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
metricsmodel (@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-onlyseriesresource 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_metricsmethod. 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-timebackfillarray seeds prior dates (incoming wins on a shared date, still field-me
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_dashboardmethod (@webframp/operator-briefing/metrics). Reads the model's own append-onlyseries(trend history) and takes an optionalreportargument — 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 ornull-bearing report is filtered, not fatal). - New
dashboardfile resource (text/html, lifetime30d,garbageCollection10). A regenerated downstream projection, so short retention is right. Written viacreateFileWriter().writeText(). redact: trueshareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, opsdetail, anddegradedReasonis 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
metricsmodel (@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-onlyseriesresource 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_metricsmethod. 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-timebackfillarray 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
(
rowsnot 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 failingwriteResourceas 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 of0is preserved as real data (0 is a number, not "absent"). Dates are validated as zero-paddedYYYY-MM-DD, which also guarantees the lexicographic
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_dashboardmethod (@webframp/operator-briefing/metrics). Reads the model's own append-onlyseries(trend history) and takes an optionalreportargument — 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 ornull-bearing report is filtered, not fatal). - New
dashboardfile resource (text/html, lifetime30d,garbageCollection10). A regenerated downstream projection, so short retention is right. Written viacreateFileWriter().writeText(). redact: trueshareable mode. Produces a variant that shows only aggregate tier counts, ops severities/labels, and non-identifying numeric trends — every reference, author, title, opsdetail, anddegradedReasonis 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
metricsmodel (@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-onlyseriesresource 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_metricsmethod. 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-timebackfillarray 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
(
rowsnot 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 failingwriteResourceas 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 of0is preserved as real data (0 is a number, not "absent"). Dates are validated as zero-paddedYYYY-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
- 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