diff --git a/SCOPE.md b/SCOPE.md index 6fb47fb..56a4887 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -1,7 +1,7 @@ --- domain: capabilities repo: activity-core -updated: "2026-06-16" +updated: "2026-07-21" --- # SCOPE @@ -26,20 +26,27 @@ lifecycle. An `ActivityDefinition` (a markdown file checked into a repo) declares a trigger (cron, one-off scheduled datetime, or named event type), context sources to resolve before evaluation, and a set of rules and instructions that determine -what tasks to create. When triggered, a durable Temporal workflow loads the -definition, resolves context, evaluates the rule/instruction set, and emits task -creation requests to issue-core or configured dry-run/audit sinks. Instructions -may also emit validated reports, and selected context resolvers may emit compact -non-secret evidence. Everything is auditable: the spawn log records the -triggering event, matched rule/instruction metadata, model/prompt hash where -applicable, and resulting task references. +what work or evidence to produce. When triggered, a durable Temporal workflow +loads the definition, resolves context, evaluates the rule/instruction set, and +emits outputs via configured sinks: + +- **Tasks** — via `IssueSink` (`rest` → issue-core, `state-hub` progress, or + `null` dry-run). +- **Reports** — instruction reports to working memory and/or State Hub progress. +- **Evidence** — compact non-secret summaries from selected resolvers (ops + inventory, package prune, legacy-meter, etc.). + +Everything is auditable: `activity_runs` records the activation; `task_spawn_log` +records emissions; report sinks leave progress/working-memory artifacts. The two evaluation modes: + - **Rule** — deterministic condition (sandboxed Python-like DSL) → fixed task templates. Fast, testable, no LLM cost. -- **Instruction** — optional pre-filter condition → LLM prompt with trusted - fields only → structured task list. For cases where the right tasks depend - on context that is easier to describe than to enumerate. +- **Instruction** — optional pre-filter → LLM or **deterministic** report path + (`model: deterministic` / `none` / `unused`) → structured tasks and/or + reports. LLM reserved for genuine judgement; deterministic for pure context + summaries. --- @@ -47,315 +54,232 @@ The two evaluation modes: - **ActivityDefinition model**: trigger config (cron / scheduled / event), context sources, rules (condition + action), instructions (trusted-field - prompt + model + output schema). + prompt + model + output schema + report sinks). - **Event type registry**: publisher-declared markdown definitions with attribute schemas, example payloads, and intent documentation. Curator-gating configurable per runtime environment. - **Trigger types**: 5-field cron with timezone and misfire policy; one-off scheduled datetime; event-type subscription via NATS; manual one-shot API trigger; one-shot schedule smoke tests for recurring definitions. -- **Context resolution adapters**: repo-scoping (repository capability queries), - State Hub (domain/workplan state, SBOM status, daily triage digest, coding - retro read model), and ops inventory (bounded HTTP/HTTPS probes of a - non-secret service inventory). The adapter registry is extensible for other - sources. -- **Rule evaluator**: sandboxed AST walker for Python-like boolean expressions - over event attributes and resolved context. Rule actions support safe - `context.*` / `event.*` interpolation and explicit `for_each` per-item - binding. No `exec()`. -- **Instruction executor**: trusted-field prompt rendering, LLM call via - llm-connect, structured output validation, item-granular recovery with a - quarantine lane and producer guardrails (count/length/depth caps, reference - allow-list) at the producer trust boundary, bounded validation-failure - artifacts for report instructions, review-required audit metadata, and - deterministic report sinks. A real downstream review queue is not implemented - in this repo. -- **Task emission adapter**: abstraction over issue-core; current transport is - REST, with `ISSUE_SINK_TYPE=null` for dry-run/audit mode. It is designed to - migrate to a durable issue-core-owned NATS command boundary when issue-core - provides that contract. -- **Report sinks**: instruction report outputs can be persisted to bounded - local working memory and posted as State Hub progress events. These are - reporting outputs, not task lifecycle ownership. -- **Ops evidence sinks**: `ops-inventory` context sources can post compact - non-secret `ops_inventory_probe` summaries to State Hub. Inter-Hub submission - is present only as a gated/deferred sink result until operator-owned - `OPS_HUB_KEY` custody and widget mapping are ready. -- **Spawn audit log**: every task emission recorded with rule/instruction id, - triggering event id, model and prompt hash (instructions), issue-core task ref. -- **Webhook receiver**: HTTP endpoint normalising inbound Gitea/GitHub webhook - payloads to EventEnvelope format and publishing to NATS. -- **Worker and workflow infrastructure**: Temporal-based durable execution — - `RunActivityWorkflow` orchestrates load → resolve → evaluate → emit. -- **REST admin API** (FastAPI): CRUD for ActivityDefinitions, manual trigger, - event type registry queries. -- **Prometheus metrics**: Temporal SDK metrics exposed for scraping. -- **Automation status surface**: deterministic, non-LLM status reporting via - `make automation-status` / `scripts/automation_status.py`, using repo-owned - evidence sources rather than coding assistant scheduler state. -- **Operational runbook**: `docs/runbook.md`. +- **Schedule reconcile**: Temporal Schedule upsert/pause with per-row error + isolation (`sync_schedules` continues after `ScheduleAlreadyRunningError`). +- **Context resolution adapters**: repo-scoping, State Hub (domain/workplan + state, SBOM status, daily triage digest, coding retro, Binky rhythm status, + consistency sweep, RecentlyOnScope hourly), shell queries (e.g. Forgejo + package prune), and ops inventory probes. Registry is extensible. +- **Rule evaluator**: sandboxed AST walker; `for_each` binding; no `exec()`. +- **Instruction executor**: trusted-field rendering, llm-connect, structured + validation, item-granular recovery, deterministic report path, report sinks. +- **Task emission adapter**: `IssueCoreRestSink`, `StateHubProgressSink`, + `NullSink` selected by `ISSUE_SINK_TYPE`. Production railiance01 currently + uses **`state-hub`** as the safe default for internal findings (see + ACTIVITY-WP-0021/0022); restore `rest` only when issue-core→Forgejo is healthy + **and** policy allows external issues. +- **Report / evidence sinks**: working memory, State Hub progress + (`daily_triage`, `sbom_staleness`, `forgejo_package_prune`, + `ops_inventory_probe`, `activity_task_spawn`, etc.). +- **Spawn audit log**: `task_spawn_log` with rule/instruction id and sink ref. +- **Webhook receiver**: Gitea/GitHub → EventEnvelope → NATS. +- **Worker and workflow infrastructure**: Temporal `RunActivityWorkflow` + (load → resolve → evaluate → report → **log_run** → emit). Emit failures no + longer skip `activity_runs` rows. +- **REST admin API** (FastAPI): CRUD, manual trigger, admin sync, metrics. +- **Automation status surface**: `make automation-status` and + `make prod-automation-status` / `scripts/prod_automation_status.sh` for + railiance01 evidence without LLM authority. +- **Operational runbook**: `docs/runbook.md`, emission boundary docs. --- ## Out of Scope -- **Task lifecycle** — creating, assigning, tracking, and closing tasks is - issue-core's responsibility. activity-core holds a spawn audit trail only. -- **Project and initiative management** — phased, completion-gated, multi-step - coordinated changes belong to project-core (future). -- **Execution of automatable tasks** — Temporal Activities that do real work - (run a scan, apply a patch, call an API) live in per-repo workers, not here. -- **General ops execution** — Kubernetes, SSH, tunnel, authenticated service - checks, secret custody, OpenBao writes, and Inter-Hub widget/API-key - provisioning belong to the owning operational repos and operator workflows. - activity-core may record non-secret probe evidence; it must not become the ops - control plane. -- **Service inventory authority** — the Custodian inventory remains owned by - the custodian/state-hub surface. activity-core may read a projected - non-secret snapshot. -- **Event broker hosting** — NATS JetStream is org infrastructure; activity-core - consumes it but does not own its lifecycle. -- **Temporal server hosting** — activity-core uses the Temporal SDK; the server - runs on Railiance infrastructure (or Docker Compose for dev). -- **End-user task UI** — tasks land in issue-core; presentation is separate. -- **Synchronous request-response patterns** — Temporal is async-first. -- **Coding assistant automation infrastructure** — assistant-provided reminders, - heartbeats, or scheduled jobs are not the execution or evidence authority for - activity-core automations. Assistants may run and summarize repo-native - commands only. +- **Task lifecycle** — create/assign/track/close remains issue-core (or fleet + work-record connectors). activity-core holds a spawn audit trail only. +- **Project and initiative management** — project-core (future). +- **General execution workers** — scans, patches, privileged API writes that + are not explicitly declared as **bounded ActivityDefinition side-effects** + (e.g. retention prune with dry-run/apply gates) belong to per-repo workers + or platform tools. +- **General ops control plane** — Kubernetes, SSH, tunnels, secret custody, + OpenBao policy administration. +- **Event broker / Temporal server hosting** — consume, do not own lifecycle. +- **End-user task UI**. +- **Coding assistant schedulers** as production authority. + +**Boundary note (side-effect resolvers):** A small set of shell/context +resolvers intentionally invoke platform tools (e.g. Forgejo package prune). +That is allowed only when the side-effect is the *declared purpose* of the +ActivityDefinition, is credential-routed, evidence-posted, and not general +task execution. It must not expand into an unbounded ops executor. --- ## Relevant When -- You need org-wide recurring maintenance automation (dependency scans, SBOM - checks, staleness audits) without bespoke per-service cron jobs. -- You need reactive task generation: "when X happens across the org, create - structured tasks in the right repos." -- You need one-off future task scheduling without a separate reminder system. -- You want an auditable record of what triggered what and why. -- You need a scheduled, non-secret evidence note proving that declared service - endpoints or access paths were observed, without executing privileged ops - commands. -- You are replacing scattered bespoke cron jobs and manual coordination with - a governed, observable automation layer. -- You need to answer "how did our automations go since Friday?" from - deterministic repo-native evidence before any optional LLM summary. - ---- +- Org-wide recurring maintenance (SBOM, package prune, legacy-meter, Binky + rhythm, consistency sweeps) without bespoke per-service cron. +- Reactive task/report generation from org events and context. +- One-off future scheduling. +- Auditable activation history (runs, spawn log, progress). +- Answering “how did automations go since Sunday?” from deterministic + repo-native / prod evidence. ## Not Relevant When -- You need to track whether a task is done, blocked, or reassigned → issue-core. -- You need to coordinate a multi-phase project with dependencies → project-core. -- You need a simple system cron with no durability requirement. -- You need synchronous request-response patterns. +- Tracking task completion/reassignment → issue-core / work records. +- Multi-phase project orchestration → project-core. +- Simple host cron with no durability or evidence needs. --- -## Current State +## Current State (2026-07-21) -- **Status**: active production-backed service with two visible open gates: - `ACTIVITY-WP-0006` still waits on three clean consecutive scheduled daily - triage runs and calibration feedback, and `ACTIVITY-WP-0008` is blocked until - Helix Forge publishes the upstream `coding_retro` read model needed to enable - the Saturday schedule. `ACTIVITY-WP-0007` is finished: the bounded - ops-inventory probe/evidence slice has live Railiance evidence. -- **Implementation**: core is functional. `RunActivityWorkflow`, - `TaskExecutorWorkflow` (stub), PostgreSQL schema, Temporal Schedules and smoke - schedules, NATS Event Router, FastAPI admin API, Prometheus metrics, event - type registry, markdown ActivityDefinition parser/sync, rule evaluator, - instruction executor, context resolvers, issue sink, report sinks, ops - evidence sink, Kubernetes deployment, and operational runbook are all - implemented. -- **Current definitions**: `weekly-sbom-staleness` is enabled and demonstrates - the deterministic rule/fan-out path. `weekly-coding-retro` is present and - tested but intentionally disabled until live `coding_retro` evidence exists. - Railiance projects the daily State Hub WSJF triage definition and the disabled - ops-service-inventory probe definition from the runtime bundle. -- **Operational proof**: the State Hub daily WSJF triage path has produced - validated reports and working-memory notes, but the calibration gate is not - closed. A 2026-06-16 recheck found State Hub `daily_triage` progress and - working-memory `daily-triage-*` notes only through 2026-06-06, so there is not - yet evidence for three clean consecutive scheduled runs after the June 7 - runtime projection failure. The ops inventory probe path has live fallback - evidence in State Hub; Inter-Hub per-entity submission remains deferred. -- **Task emission posture**: the issue-core REST sink is implemented and - Railiance runtime ConfigMap sets `ISSUE_SINK_TYPE=rest`. `ISSUE_CORE_API_KEY` - is synced into `actcore-runtime-secret` by ExternalSecret - `actcore-issue-core-runtime` (OpenBao path shared with issue-core). Bootstrap - the ESO token with `make openbao-eso-token-apply`. `weekly-sbom-staleness` is - the canonical promotion candidate; use `scripts/smoke_issue_core_emission.py` - before trusting production task creation. -- **Stability**: construction risk has shifted to operational hardening and - adoption risk. The last recorded full-suite pass in the workplans was - 2026-06-04 (`128 passed, 1 skipped`), with later targeted coverage added for - ops inventory, ops evidence sinks, Railiance projection wiring, and weekly - coding retro parsing/rule behavior. -- **Next**: close `ACTIVITY-WP-0006-T03` with real scheduled-run calibration - evidence; close `ACTIVITY-WP-0008-T03` once upstream `coding_retro` publication - exists and the dry-run/duplicate check passes; decide when to move selected - task/report/evidence sinks from dry-run or fallback mode to their intended - live backends. +### Status + +Production on **railiance01** (`activity-core` namespace). Recent finished +workplans: + +| WP | Outcome | +| --- | --- | +| ACTIVITY-WP-0018 | Own-infra automation status CLI | +| ACTIVITY-WP-0019 | Automation inventory targets | +| ACTIVITY-WP-0020 | Weekly Forgejo package prune **enabled**; first apply 38 deletes | +| ACTIVITY-WP-0021 | Prod reliability: state-hub sink, log_run-before-emit, schedule harden, DB probes, prod status path | +| ACTIVITY-WP-0006/0008 | Marked finished historically; enablement evidence has moved | + +Open product/policy workplan: **ACTIVITY-WP-0022** (IssueSink no-default-Forgejo). + +### Live posture (railiance01) + +- Image: `activity-core:railiance01-prod` (locally imported). +- `ISSUE_SINK_TYPE=state-hub` (internal findings → State Hub progress, not + Forgejo issues). +- Edge relay: `actcore-statehub-edge-relay` → in-cluster `state-hub`. +- Weekly prune: worker has `FORGEJO_TOKEN` + hostPath `/opt/railiance-platform` + + `live_images_file` (kubectl absent in pod). +- Proven one-shots (2026-07-21): Binky daily/mail COMPLETED with tasks_spawned=1; + SBOM deterministic report; daily triage progress; prune apply. + +### Definitions (repo files + prod DB) + +| Definition | Role | +| --- | --- | +| `weekly-sbom-staleness` | Deterministic SBOM report; task emit gated off | +| `weekly-forgejo-package-prune` | Sunday 03:30 UTC apply prune + evidence | +| `weekly-legacy-meter-review` / `legacy-meter-8h-capture` | Meter evidence | +| `weekly-coding-retro` | Present; enablement depends on `coding_retro` feed | +| Binky daily / mail / review-prep | Rhythm tasks via IssueSink | +| Railiance ConfigMap bundle | Daily triage, ROS hourly, consistency sweep, etc. | + +### Task emission posture + +- **Canonical REST sink** to issue-core remains implemented and documented. +- **Production default is `state-hub`** after Forgejo PAT/backend failures and + fleet policy against silent Forgejo issues (WP-0021 path B, WP-0022). +- Restoring `rest` requires healthy issue-core→Forgejo **and** explicit policy + opt-in per definition. --- ## Assessment Against Intent -activity-core now matches the core intent: it answers **when** coordination -work should happen, **what** work should be created from current org context, -and **where** each work item should land. The daily WSJF triage is the clearest -judgement-oriented proof point; weekly SBOM staleness is the clearest -deterministic-rule proof point. +### Alignment -The governing boundary still matters. activity-core should keep owning trigger -durability, context resolution, rule/instruction evaluation, report/task -emission, and spawn/report audit. It should not become the task lifecycle -database, the project planner, or a general execution worker. The local -`TaskExecutorWorkflow` remains a stub and should stay that way unless a future -workplan explicitly rehomes execution responsibility. +| INTENT promise | Status | +| --- | --- | +| Answers **when / what / where** | Met — Temporal schedules, rules/instructions, sinks | +| Markdown definitions | Met — `activity-definitions/`, event-types, external ConfigMaps | +| Rules before instructions | Met — SBOM/prune/Binky rules; triage uses LLM when needed | +| Durable recurring automation | Met — railiance01 schedules fire; status surface exists | +| Audit trail | Met — `activity_runs`, spawn log, progress/working-memory | +| Does not own task lifecycle | Met — no completion tracking | +| Does not own project phases | Met | -One boundary nuance is now explicit: activity-core may post State Hub progress -events as a configured report or evidence sink. That is acceptable because it -records the result of an activity-core activation; it is not ownership of State -Hub state, task lifecycle, or workplan planning. +### Gaps and tensions (INTENT ↔ practice) -The main drift risk is convenience creep: adding direct task tracking, -project-phase state, or bespoke operational scripts because the Temporal -substrate is already nearby. Future work should prefer declarative -ActivityDefinitions, bounded context resolvers, and outbound adapters over -new one-off control paths. +| Gap | Severity | Notes | +| --- | --- | --- | +| **G1. Sink default vs INTENT “emit to issue-core”** | High (policy) | INTENT names issue-core as the task landing zone. Practice and work-record canon push **State Hub / repo work records** for internal findings. WP-0022 owns policy; code already supports `state-hub` / `null` / `rest`. | +| **G2. Executor gap** | High (value) | Tasks are emitted (progress refs or issue-core), but **no per-repo executor** reliably consumes them (Binky briefs still need harness/agent pickup). INTENT assigns execution to per-repo Temporal workers — that substrate is thin. | +| **G3. Side-effect resolvers** | Medium | Forgejo prune `apply: true` runs platform deletes inside a context resolver. Allowed only as declared, gated side-effect; needs clearer SCOPE language (above) and operator refresh of live-images protection. | +| **G4. Review queue** | Medium | `review_required` remains metadata-only; no downstream review queue. | +| **G5. TaskExecutorWorkflow stub** | Low–medium | Still registered; risk of attracting real execution. | +| **G6. ROS digest completeness** | Medium (ops) | Template file mounted; MarkiTect CLI missing in state-hub image → digests still fail per domain. | +| **G7. Credential delivery** | Medium (ops) | `FORGEJO_TOKEN` bootstrap-injected; ESO 403 on forgejo-admin path. issue-core `GITEA_BACKEND_TOKEN` still broken for path A rest sink. | +| **G8. Live-images hygiene** | Medium (ops) | Multi-cluster `live-images-all.txt` must be refreshed after deploys or prune can delete live tags (incident 2026-07-21, restored). | +| **G9. Evidence federation** | Low | Progress often lands on railiance01 edge/hub; workstation primary hub may not show the same feed without tunnel/outbox health. | +| **G10. API external access** | Low | ClusterIP-only; intentional until auth policy. | -## Known Gaps Against Intent +### Drift risks -- **Scheduled-run trust gap**: INTENT promises recurring coordination work that - runs without Bernd as the manual coordination layer. The daily triage path is - implemented, but its current calibration task still lacks three clean - consecutive scheduled runs after the June 7 runtime failure. Until that closes, - daily triage remains a production-backed capability with an evidence gap, not - a fully proven standing substrate. -- **Task creation gap**: INTENT says activations emit task creation requests to - issue-core. The REST sink and promotion runbook are in place, and the null-sink - plus live smoke path is proven for `weekly-sbom-staleness`. Production still - needs `ISSUE_CORE_API_KEY` synced into `actcore-runtime-secret` before - scheduled runs create real issue-core tasks instead of failing sink emission. -- **Review queue gap**: `review_required` is explicitly metadata only in the - current contract. No issue-core review queue integration exists here, so any - future queue routing needs a downstream issue-core contract before high-impact - instruction outputs rely on it. -- **Evidence backend posture**: the State Hub fallback evidence path is the - accepted current backend for `ops_inventory_probe`. Inter-Hub/ops-hub - submission is deliberately deferred behind `OPS_HUB_KEY`, widget mapping, and - operator approval, so per-entity ops evidence publication is future work. -- **Execution-boundary residue**: `TaskExecutorWorkflow` is still registered as - a stub that writes a done `task_instances` row. It should remain inert or be - removed/re-homed before it attracts real execution work, because execution is - explicitly outside activity-core's intent. -- **API exposure posture**: the FastAPI surface stays ClusterIP-only for now. - External ingress remains future work until an authenticated access policy is - designed. +1. **Convenience execution** — growing shell resolvers into a general ops runner. +2. **Silent sink restore** — flipping `ISSUE_SINK_TYPE=rest` without policy + + healthy Forgejo backend reintroduces issue spam / 503s. +3. **Protection file staleness** — weekly prune with `apply: true` depends on + fresh live-image lists. +4. **Stub workflow attraction** — `TaskExecutorWorkflow` looks like an + execution home. --- ## How It Fits ``` -[NATS JetStream] ← publishers: State Hub, Gitea webhooks, Temporal signals, cron +[NATS JetStream / Temporal Schedules / manual trigger] ↓ -[activity-core] ← event type registry, rule evaluator, instruction executor -[activity-core] → [issue-core] → [repos/services] -[activity-core] → [report/evidence sinks] → [State Hub / working memory / future Inter-Hub] +[activity-core] Event type registry · rules · instructions · context resolvers + ↓ +[IssueSink: rest | state-hub | null] → issue-core or State Hub progress +[report/evidence sinks] → State Hub / working memory +[bounded shell side-effects] → platform tools (e.g. package prune) ``` -- **Upstream**: NATS (event bus), Temporal (durable workflow engine), PostgreSQL - (definitions and audit log), repo-scoping (context adapter), State Hub (context - adapter and event publisher). -- **Downstream**: issue-core (task management) and configured report/evidence sinks. - Agents and humans pick up tasks from issue-core and do the actual work. - Railiance may use the null sink for dry-run/audit mode until live issue-core - emission is approved. -- **Coordinates with**: the state hub delegates maintenance automations to - activity-core by publishing lifecycle events or by being resolved as context. - activity-core may post progress events as report/evidence outputs, but it - does not own State Hub task/workplan state. +- **Upstream**: NATS, Temporal, PostgreSQL, State Hub, repo-scoping, llm-connect. +- **Downstream**: issue-core (optional), State Hub, platform tools, future + per-repo executors / agent-harness. +- **Ops**: railiance01 k3s; workstation status via SSH helper. --- ## Terminology -- **ActivityDefinition** — a markdown file declaring trigger, context sources, - rules, and instructions. The unit of automation policy. -- **EventEnvelope** — the canonical internal event format; normalises all inbound - events (NATS, webhooks, cron signals) to a common structure. -- **Rule** — deterministic condition expression + task template action. Evaluated - by a sandboxed AST walker. -- **Instruction** — LLM-evaluated task generation with trusted-field prompt - interpolation and structured output schema enforcement. -- **Report sink** — configured persistence for instruction reports, currently - working-memory markdown notes and State Hub progress events. -- **Evidence sink** — configured persistence for compact non-secret resolver - evidence, currently State Hub progress for ops inventory probes; Inter-Hub is - a deferred gated target. -- **Event type** — a registered, schema-documented category of event (e.g. - `org.repo.registered`). Publisher-declared; curator-gated per environment. -- **Spawn audit trail** — activity-core's local record of what tasks were emitted, - to which issue-core backend, and under which rule/instruction. Not the - authoritative task record. -- Potentially confusing: **Activity** (Temporal concept — a single executable - step in a workflow) vs. **ActivityDefinition** (app concept — the policy record - that governs what gets spawned). These are different things. +- **ActivityDefinition** — markdown policy unit (trigger + context + rules/instructions). +- **EventEnvelope** — canonical inbound event shape. +- **Rule / Instruction** — deterministic vs judgement (or deterministic report) paths. +- **IssueSink** — task emission adapter (`rest` / `state-hub` / `null`). +- **Report sink / Evidence sink** — non-task activation outputs. +- **Spawn audit trail** — local emission record; not authoritative task state. +- **Activity** (Temporal) vs **ActivityDefinition** (app policy) — different concepts. --- ## Related / Overlapping -- `issue-core` (formerly issue-facade) — downstream task management; receives - all task emission from activity-core. -- `repo-scoping` — context adapter for repository capability queries. -- `the-custodian` / State Hub — context adapter for domain state; delegates - maintenance automation to activity-core via NATS events. -- `llm-connect` — instruction execution backend for judgement-oriented reports - such as daily State Hub WSJF triage. -- `core-hub` / `ops-hub` — production ops evidence intake (`hub.coulomb.social`); - historical Haskell Inter-Hub is `inter-hub-haskell` (retired 2026-07-08). -- `rules-core` (future extraction) — the rule evaluator and instruction executor - module, currently in `src/activity_core/rules/`. -- `project-core` (future) — project and initiative management; will use - activity-core to generate per-phase task sets. -- `ops-bridge` — SSH tunnel to remote Temporal server on Railiance. +- `issue-core` — task connector / external tracker mapping (not fleet work-record origin). +- `repo-scoping`, State Hub / the-custodian, `llm-connect`, `agent-harness`. +- `railiance-platform` — Forgejo package prune tool and credential lanes. +- `ops-warden` — credential routing (not secret vending for non-SSH). +- `project-core` (future), `ops-bridge` tunnels. --- ## Architecture Decisions -- `docs/adr/adr-001-event-bridge-architecture.md` — overall Event Bridge pattern, - boundaries, state hub relationship, domain assignment. -- `docs/adr/adr-002-definition-format.md` — markdown-as-definition format, - governance model, event type schema, ActivityDefinition structure. -- `docs/adr/adr-003-rule-instruction-model.md` — Rule DSL, Instruction safety - model, evaluation semantics, audit trail, testing strategy. -- `docs/adr/adr-004-producer-trust-boundary.md` — untrusted-producer premise, - trust-but-handle vs verify-and-mitigate postures, error-locality and - quarantine-with-provenance, producer guardrails for LLM/agent/human output. +- `docs/adr/adr-001-event-bridge-architecture.md` +- `docs/adr/adr-002-definition-format.md` +- `docs/adr/adr-003-rule-instruction-model.md` +- `docs/adr/adr-004-producer-trust-boundary.md` --- ## Getting Oriented -- Start with: `INTENT.md` (why), this file (what), `docs/adr/` (decisions). -- Key source files: `src/activity_core/models.py` (domain model), - `src/activity_core/workflows.py` (RunActivityWorkflow), - `src/activity_core/activities.py` (Temporal activities), - `src/activity_core/event_router.py` (NATS → Temporal), - `src/activity_core/schedule_manager.py` (Temporal Schedules), - `src/activity_core/api.py` (FastAPI admin), - `src/activity_core/report_sinks.py` (instruction reports), - `src/activity_core/ops_evidence_sinks.py` (ops evidence), - and `src/activity_core/context_resolvers/` (external context adapters). -- Definition files: `event-types/`, `activity-definitions/`, and `tasks/`. -- Dev environment: `docker-compose.dev.yml` (Temporal + PostgreSQL + NATS). -- Entry points: `uv run python -m activity_core.worker` (Temporal worker), - `uv run uvicorn activity_core.api:app --port 8010` (admin API). +- Start: `INTENT.md`, this file, `docs/adr/`, `docs/runbook.md`. +- Key code: `workflows.py`, `activities.py`, `issue_sink.py`, `report_sinks.py`, + `context_resolvers/`, `automation_status.py`, `sync_schedules.py`. +- Definitions: `activity-definitions/`, `event-types/`, Railiance ConfigMaps. +- Status: `make automation-status SINCE=sunday` · + `make prod-automation-status SINCE=sunday`. --- diff --git a/workplans/ACTIVITY-WP-0023-intent-scope-gap-closure.md b/workplans/ACTIVITY-WP-0023-intent-scope-gap-closure.md new file mode 100644 index 0000000..5284f23 --- /dev/null +++ b/workplans/ACTIVITY-WP-0023-intent-scope-gap-closure.md @@ -0,0 +1,254 @@ +--- +id: ACTIVITY-WP-0023 +type: workplan +title: "Intent–scope gap closure and WP-0020/0021 operational follow-ups" +domain: infotech +repo: activity-core +status: proposed +owner: codex +topic_slug: activity-core +created: "2026-07-21" +updated: "2026-07-21" +--- + +# Intent–scope gap closure and WP-0020/0021 operational follow-ups + +## Origin + +2026-07-21 gap analysis of `INTENT.md` against production practice and the +refreshed `SCOPE.md` (same day). Captures: + +1. **Product/architecture gaps** vs the governing when/what/where principle. +2. **Non-blocking operational follow-ups** from ACTIVITY-WP-0020 (Forgejo prune) + and ACTIVITY-WP-0021 (prod reliability). + +Does **not** re-implement ACTIVITY-WP-0022 (IssueSink default policy) — that +workplan owns G1 policy decisions; this workplan **consumes** its outcomes and +covers adjacent gaps. + +## Gap summary (from SCOPE) + +| ID | Gap | Intent tension | +| --- | --- | --- | +| G1 | Sink default vs “emit to issue-core” | Policy — **ACTIVITY-WP-0022** | +| G2 | Executor gap (tasks emit, work not executed) | INTENT assigns execution to per-repo workers | +| G3 | Side-effect resolvers (prune apply) | Must stay bounded/declared | +| G4 | `review_required` has no queue | Downstream contract missing | +| G5 | `TaskExecutorWorkflow` stub attraction | Execution boundary residue | +| G6 | ROS digests need MarkiTect | Ops completeness | +| G7 | Credential delivery (FORGEJO_TOKEN ESO; issue-core Gitea PAT) | Path A / weekly prune durability | +| G8 | `live-images-all.txt` hygiene | Prune safety after deploys | +| G9 | Evidence federation workstation vs edge hub | Operator visibility | +| G10 | ClusterIP-only API | Deferred auth | + +## Goal + +Close or explicitly disposition each gap with either shipped code/docs, +operator-owned policy (WP-0022), or a deliberate “wontfix / external owner” +note — so SCOPE stays truthful and INTENT’s three questions remain load-bearing. + +## Out of scope + +- Implementing fleet work-record promotion (state-hub / the-custodian). +- Full agent-harness product roadmap (only the activity-core emission contract). +- OpenBao policy authorship for unrelated workloads. +- Re-opening finished WP-0006/0008 calibration narratives unless evidence is + still broken after WP-0021 triage fixes. + +## Tasks + +## Task: Align sink matrix with INTENT and WP-0022 + +```task +id: ACTIVITY-WP-0023-T01 +status: wait +priority: high +``` + +**Depends on ACTIVITY-WP-0022-T01** (default sink policy decision). + +1. After WP-0022 decides defaults, update `INTENT.md` wording if the fleet no + longer treats issue-core as the **default** landing zone (keep issue-core as + optional external connector). +2. Ensure `docs/issue-core-emission-boundary.md` + runbook sink matrix match: + `null` / `state-hub` / `rest` + per-definition opt-in. +3. Confirm railiance01 env and ConfigMap defaults match the decision (today: + `state-hub`). + +**Done when:** INTENT + emission docs + prod defaults tell one story; WP-0022 +tasks for docs/defaults are cross-linked as done. + +## Task: Executor contract for emitted tasks (Binky first) + +```task +id: ACTIVITY-WP-0023-T02 +status: todo +priority: high +``` + +INTENT: execution lives in per-repo workers / harness — not activity-core. + +1. Document the **consumer contract** for `activity_task_spawn` (state-hub) and + issue-core REST refs: required fields, idempotency, target_repo. +2. Prove one end-to-end path for **Binky daily brief**: emit → consumer + (agent-harness or documented human lane) → `binky_daily_brief` progress / + brief artifact. +3. File or link harness/railiance work if the consumer is out of this repo; + do not implement a real `TaskExecutorWorkflow` here. + +**Done when:** A scheduled or one-shot Binky daily produces both a spawn record +**and** a Binky-side completion evidence note within one business day of fire. + +## Task: Side-effect resolver guardrails + +```task +id: ACTIVITY-WP-0023-T03 +status: todo +priority: medium +``` + +1. Codify in runbook which shell queries may set `apply: true` (today: Forgejo + package prune only). +2. Hard-fail prune apply when `live_images_file` is missing or empty when + `apply: true` (prevents 2026-07-21 worker incident recurrence). +3. Optional: unit test that apply without protection file is rejected. + +**Done when:** apply path cannot run without an explicit non-empty protection +source; docs list allowed side-effect definitions. + +## Task: Live-images protection refresh automation + +```task +id: ACTIVITY-WP-0023-T04 +status: todo +priority: medium +``` + +Non-blocking follow-up from ACTIVITY-WP-0020. + +1. Script (railiance-platform or activity-core `scripts/`) that exports live + forgejo images from coulombcore + railiance01 and merges to + `railiance-platform/docs/evidence/live-images-all.txt` on the worker host. +2. Document cadence (post-deploy checklist or weekly pre-prune cron on host). +3. Prefer non-secret output only (image refs, no tokens). + +**Done when:** operator can refresh protection with one documented command; +runbook links it from the prune section. + +## Task: FORGEJO_TOKEN via ESO (retire bootstrap inject) + +```task +id: ACTIVITY-WP-0023-T05 +status: todo +priority: medium +``` + +1. OpenBao / railiance-platform: grant activity-core ESO token read on + `platform/workloads/forgejo/forgejo-admin` **or** a dedicated + `activity-core` prune token with package write only. +2. Land ExternalSecret merge into `actcore-runtime-secret` `FORGEJO_TOKEN`. +3. Remove reliance on one-shot `kubectl patch secret` bootstrap. + +**Done when:** ExternalSecret Ready=True and worker restarts still see a +working token without manual patch. + +## Task: issue-core path A (optional rest sink) + +```task +id: ACTIVITY-WP-0023-T06 +status: todo +priority: low +``` + +Non-blocking follow-up from ACTIVITY-WP-0021. + +1. Rotate/fix issue-core `GITEA_BACKEND_TOKEN` so `POST /issues/` returns 201 + (not 503 forgejo-inbox). +2. Smoke from actcore-worker with `ISSUE_SINK_TYPE=rest` only for definitions + that opt in (per WP-0022). +3. Do **not** flip global default to rest without WP-0022. + +**Done when:** documented smoke 201 for one opt-in definition, or explicit +wontfix with issue-core owning the backend fix only. + +## Task: ROS MarkiTect completeness + +```task +id: ACTIVITY-WP-0023-T07 +status: todo +priority: medium +``` + +1. Coordinate with state-hub image: ship MarkiTect / set + `STATE_HUB_MARKITECT_CLI_PATH` so `/recently-on-scope/hourly` does not fail + per-domain with MarkiTect-required errors. +2. Template `COPY templates/` already landed; verify after image roll. +3. Re-trigger ROS hourly; confirm `failed` list empty or only non-template + reasons. + +**Done when:** one clean ROS hourly context snapshot without missing-template +or MarkiTect-missing errors for configured domains. + +## Task: Retire or quarantine TaskExecutorWorkflow + +```task +id: ACTIVITY-WP-0023-T08 +status: todo +priority: low +``` + +1. Decide: remove registration from worker, or rename/document as + legacy-no-op with metrics alert if used. +2. Ensure no ActivityDefinition or API path depends on it. +3. Update SCOPE if removed. + +**Done when:** stub cannot attract production execution by accident. + +## Task: Review-required disposition + +```task +id: ACTIVITY-WP-0023-T09 +status: todo +priority: low +``` + +1. Document that `review_required` is metadata-only until issue-core or + work-record review lane exists. +2. Either file a cross-repo task for a real review queue **or** mark as + wontfix / future with link in SCOPE known gaps. + +**Done when:** SCOPE G4 has a disposition date and owner, not an open lie. + +## Task: Evidence visibility note (edge vs workstation hub) + +```task +id: ACTIVITY-WP-0023-T10 +status: todo +priority: low +``` + +1. Document in runbook: prod progress is on railiance01 state-hub/edge; use + edge query or tunnel, not only workstation `127.0.0.1:8000` history. +2. Optional: `prod-automation-status` prints last N edge progress event types + for `daily_triage` / `forgejo_package_prune` / `activity_task_spawn`. + +**Done when:** an operator following runbook can find post-fire evidence without +guessing hub topology. + +## Success criteria + +- [ ] G1 closed via WP-0022 + T01 doc alignment +- [ ] G2 has a proven Binky executor path or explicit external workplan +- [ ] G3 apply-without-protection is impossible +- [ ] G6–G8 operational follow-ups shipped or scheduled with owners +- [ ] G5/G9/G10 dispositioned +- [ ] `SCOPE.md` re-checked after close; no stale “rest default / WP-0006 gate” + language + +## References + +- `INTENT.md`, `SCOPE.md` (2026-07-21 refresh) +- `ACTIVITY-WP-0020` closeout (prune enable, live-images, token bootstrap) +- `ACTIVITY-WP-0021` closeout (state-hub sink, schedule harden, ROS template) +- `ACTIVITY-WP-0022` IssueSink no-default-Forgejo +- `docs/issue-core-emission-boundary.md`