Skip to content
Back to skills

Portfolio Watch

ASecurity

Show the recurring, read-only portfolio summary for the Seshat BI repo -- every governed scope's covered-dimension findings (source drift, contract/metric drift, dashboard-intent divergence, readiness, approvals, review), open blockers, human-attention flag, and ONE prioritized next action, plus a baseline diff against the last run (new/resolved/unchanged). Use when someone asks "run portfolio watch", "what changed since last week", "show me the recurring summary", or "which scopes need a hum...

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
datagogitdatabase

Works with

  • cli

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add Kemetra/Seshat-BI --skill portfolio-watch --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Portfolio Watch?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Portfolio Watch
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/kemetra-portfolio-watch/badge)](https://www.skillsdirectory.com/skills/kemetra-portfolio-watch)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: portfolio-watch
description: >-
  Show the recurring, read-only portfolio summary for the Seshat BI repo --
  every governed scope's covered-dimension findings (source drift,
  contract/metric drift, dashboard-intent divergence, readiness, approvals,
  review), open blockers, human-attention flag, and ONE prioritized next
  action, plus a baseline diff against the last run (new/resolved/unchanged).
  Use when someone asks "run portfolio watch", "what changed since last week",
  "show me the recurring summary", or "which scopes need a human, and what
  changed". READ-ONLY and invoke-and-present only: it AGGREGATES evidence that
  shipped surfaces already produce (it runs NO new check, re-derives NOTHING);
  it persists a LOCAL baseline snapshot under `.seshat/watch/` so the next run
  can diff; it introduces NO new gate/rule/approval mechanism and emits NO
  fabricated health/confidence/priority score (every line is a shipped
  categorical status, a shipped finding enum, or a measured magnitude traced
  to a committed source).
---

# portfolio-watch

Portfolio Watch answers one recurring question: *since we last looked, what changed,
what still needs a human, and what is the one next thing to do per scope?* It is the
baseline-diffable, multi-dimension EXTENSION of the point-in-time `retail-control-room`
roll-up (F012) -- same read-only, aggregate-never-re-derive posture, plus a persisted
snapshot and the drift/semantic-drift/dashboard-intent-divergence dimensions the control
room does not fold in.

## Scope wall (read first)

- **Aggregates, never re-derives.** Every finding is sourced from a shipped surface's
  already-committed output (`drift.py`/`drift_semantics.py`, `metric_drift.py`,
  `semantic_audit.py`/`report_intent.py`, `readiness_projection.py`/`readiness_classify.py`,
  `approval_inbox.py`, `review_integration.py`/`review_pack_export.py`). It runs NO new
  check and calls NONE of those surfaces' own comparators itself -- it reads what they
  already recorded and cites the path.
- **No new gate / rule / approval mechanism.** This is a Tier-5 read/summarize/derive
  companion (roadmap binding rule), not another governance engine. `seshat check`'s rule
  inventory and exit behavior are unchanged by this skill's existence.
- **No score, ever.** Only the four readiness spine statuses, the shipped categorical
  finding enums (relayed verbatim), and measured magnitudes (counts/rates/deltas) traced
  to a committed source appear anywhere. A health/confidence/priority/quality number is
  never emitted (hard rule #9) -- if asked for one, decline and point here.
- **No live database in the MVP.** The governed-scope set comes from committed
  `mappings/*/readiness-status.yaml` paths (the same set `status_surface` /
  `readiness_projection` already track), never a live metadata query. A dimension whose
  evidence needs a live re-profile with no DSN configured is truthfully `[PENDING LIVE]`.
- **Relays Principle-V, decides none of it.** A grain/PII/returns/rollup/identity/approval
  condition is relayed with a named owner; this skill originates no ruling on any of them.
  `requires_human_attention` fires independently of category rank whenever an unmet
  approval or a relayed Principle-V/PII drift blocker is present -- it can never be buried
  by a higher-ranked, less dangerous condition.
- **"Recurring" = re-runnable + baseline-diffable, not a scheduler.** There is no cron, no
  hosted monitoring, no continuous-run surface here or planned by this skill.

## What it aggregates (the six covered dimensions)

| Dimension | Source it relays | Truthful degradation |
|---|---|---|
| Source drift | `drift.py` / `drift_semantics.py` committed findings | no live re-profile recorded -> `[PENDING LIVE]` |
| Contract/metric drift | `metric_drift.py` verdicts (a committed record of a `retail semantic-check` run) | no recorded run -> `not_applicable_with_reason` |
| Dashboard-intent divergence | `semantic_audit.py` / `report_intent.py` committed findings | no recorded run -> `not_applicable_with_reason` |
| Readiness (+ changed readiness) | `readiness_projection.py` / `readiness_classify.py` | a malformed readiness-status.yaml -> `unreadable` for that scope, never dropped |
| Stale/missing approvals | `approval_inbox.py` | (read directly; always covered or unreadable) |
| Review (tables requiring attention) | `review_integration.py` / `review_pack_export.py` committed result | no recorded result -> `not_applicable_with_reason` |

Every dimension is one of the five closed states: `covered` (cites its evidence) |
`[PENDING LIVE]` | `stale` (cites captured-at vs current HEAD) | `not_applicable_with_reason`
(names why) | `unreadable` (names the unknown schema version / read error). No state is
ever silently upgraded to `covered`, and one scope's read error never aborts the run --
a partial portfolio is summarized for the covered scopes, with the un-evidenced ones
listed in `portfolio.scopes_with_no_evidence`.

## The one prioritized next action per scope

Selected by the SHIPPED fixed `readiness_classify` rank (`approval` > `grain` >
`live_validation` > `artifact` > `readiness`) over that scope's own open readiness
blockers; the `action` text is that scope's own recorded `next_action`, RELAYED verbatim
-- never synthesized. Two scopes tying on the same top category each surface their own
action; the rank is a committed lookup, never broken by an invented number.

## The baseline diff (the genuinely new part over the control room)

Each run reads the prior local snapshot (`.seshat/watch/snapshot.json`), diffs the
current magnitude-free Condition Keys against it, and writes a fresh snapshot:

- No prior snapshot (first run, or a corrupt one) -> every condition is
  `current_condition_no_baseline` -- explicitly NOT `new` -- and the summary states that
  no baseline was available (mirrors `drift.py`'s `observed=None` first-run honesty).
- A prior snapshot exists -> each condition is `new` / `resolved` / `unchanged`. A
  magnitude wiggle on the SAME class/locator never churns as new/resolved (duplicate
  suppression) -- only a genuinely new or genuinely resolved condition moves.
- A scope added/removed between runs is reported as a scope-level change, never
  misattributed as a condition change inside a scope that no longer exists (or does not
  exist yet).

## Run it

Invoke `build_portfolio_watch_summary` / `run_portfolio_watch` from `seshat.portfolio_watch`
(the pure aggregator library), or the one narrow CLI surface for CI/agent-less use:

```
retail watch --format json
retail watch --format text
```

Present the result: per scope, `current_stage`, the covered-dimension findings (state +
class + evidence + owner where relevant), `open_blockers`, `requires_human_attention` (+
owner when set), the one `prioritized_next_action`, and the `change_labels` against the
prior snapshot. Close with the `portfolio` block (measured `scope_count` /
`scopes_requiring_attention_count` / `scopes_with_no_evidence`) and note that the run
wrote a fresh local snapshot for next time.

## No fake confidence (the guardrail)

If asked for "a portfolio health score", "a percent-ready", or "one confidence number",
DECLINE: cite hard rule #9 and this skill's frontmatter, and return the four statuses +
the shipped categorical enums + the measured magnitudes with their source paths instead.

## Read-only proof

After a run, `git status` shows zero modified files under `mappings/` (or any other
committed per-scope artifact) -- the only new/changed path is the local
`.seshat/watch/snapshot.json` (git-ignored by default). No approval is recorded, no
readiness stage moves to `pass`, no database is opened, nothing is published.

## See also

- The closest shipped sibling (same posture, no baseline/no extra dimensions):
  `.claude/skills/retail-control-room/SKILL.md` (F012). Portfolio Watch EXTENDS this
  posture; it does not fork or replace it.
- The aggregator library + snapshot format: `src/seshat/portfolio_watch.py`.
- The tool doc: `docs/tools/portfolio-watch.md`.
- The feature spec: `specs/131-portfolio-watch/spec.md` (+ `data-model.md`, `contracts/`).
- The gates it reads (never re-runs): `retail-govern` / `seshat check`,
  `retail-semantic-check`, `retail-validate`; the readiness model:
  `docs/readiness/readiness-model.md`; the source-drift precedent:
  `docs/readiness/source-drift.md`.
- The ratified CLI-vs-skill decision behind the one narrow `retail watch` surface:
  `docs/roadmap/decisions/cli-verbs-vs-skill-driven.md`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…