--- id: FI-WP-0005 type: workplan title: "Move the daily brief to a profiled, granted execution on activity-core infrastructure" domain: agents repo: freedom-intelligence status: active flavor: implementation owner: claude topic_slug: freedom-intelligence priority: high created: "2026-09-22" updated: "2026-09-22" depends_on: - FI-WP-0004 related: - REINAH-WP-0003 - ACT-ADR-006 - ACT-ADR-007 - ACTIVITY-WP-0032 - ACTIVITY-WP-0038 state_hub_workstream_id: "00f3ba5e-270d-559d-afb6-8b382507c902" --- # FI-WP-0005 — Profiled brief execution ## Origin rein-aharness message `d0b45acb` (2026-09-04, REINAH-WP-0003-T04): profile-absent routing now depends on `AGENT_HARNESS_LEGACY_APPROACHES_UNTIL` (example expiry **2026-12-31**). FI must supply an owner-approved replacement for `fi-daily-research-brief`: a versioned profile, input schema, allowed paths, completion evidence, model route, rollback pin and a separate publication decision. FI replied 2026-09-22 (`74afc283`): FI-WP-0004-T04 already removed the swallowed push failure; the declaration follows this workplan. ## Decisions (operator, 2026-09-22) 1. **Publication is generic infrastructure.** Request a repository-grant v2 in activity-core with a typed publication field. Do not keep the push as an FI-specific rein capability. 2. **Execution shape B.** The brief runs as an agent under a versioned Glas profile. Its sandbox can reach only the model route and the FI source hosts. The current single llm-connect call writes from model memory, and that caused the V4-Flash mis-sizing. 3. **Generic due check now.** Propose to activity-core replacing the FI-specific `fi_brief_status` resolver with a parameterised published-artifact resolver. FI is the first user. 4. **Break-glass host timer:** retire it (T06, rationale below). ## Responsibilities | Layer | Owns for this job | Does not own | |---|---|---| | freedom-intelligence | Definition, inputs, allowed paths, quality rules, source host list, publication decision, durability verifier, canary acceptance | Scheduling code, profile catalog, sandboxes | | activity-core | Schedule, due resolution, `ops_run` emission carrying `harness_profile_ref` + `repository_grant`, grant validation, close reconciliation and evidence | Executing anything (ADR-006 §4); the profile catalog | | glas-harness | Profile `harness.fi-research-brief`: rein, sandbox, tool profile, model route, limits, rollback pin | What the brief says; when it runs | | sand-boxer | Isolation and the per-host HTTPS egress allowlist (`docs/bwrap-egress.md`) | Which hosts FI needs | | rein-aharness | Inner loop; grant enforcement (paths, commits, publication); drops label routing and Binky model env fallbacks | Publication policy | Reused as-is: `harness_profile_ref` (WP-0032), grant v1 path and commit validation plus close reconciliation (WP-0038), profile version pinning as rollback. Gaps: grant v1 rejects `publish: true`; `fi_brief_status` is tenant-specific code in shared infrastructure; no Glas profile allows network egress beyond a model provider. ## Tasks ### T01 — Owner declaration v1 ```task id: FI-WP-0005-T01 status: done priority: high state_hub_task_id: "bf8c1870-bdca-51d6-beaf-c5f000037205" ``` Write `activity-definitions/fi-daily-research-brief.declaration.yaml` (or an equivalent section in the definition) stating: input set (files and prior brief window), output path `briefs/YYYY/MM/YYYY-MM-DD.md`, allowed paths, commit count (exactly 1), completion evidence (`fi_daily_brief` with `pushed=true`, `origin_sha`, path, date), required model class and tool use, quality rules (catalog is the authority, no invented sizes, no re-announce), publication policy (reference T02), and rollback. No Binky-named env vars. **Done when:** the declaration is committed, and every field rein listed in `d0b45acb` maps to a concrete value or to a named follow-up task here. **2026-09-22:** Done. `activity-definitions/fi-daily-research-brief.declaration.yaml` (status `proposed`). It covers profile ref (pending T05), inputs, outputs, grant (its v1 fields validate against activity-core `RepositoryGrant`; publication pending T04), quality rules, model requirements without env selection, completion evidence and rollback pins. `scripts/test_declaration.py` checks it. Open operator question: whether a pinned agent executable inside the Glas sandbox satisfies the playbook's "no Claude Code / Codex on railiance01" rule. ### T02 — Publication decision record ```task id: FI-WP-0005-T02 status: done priority: high state_hub_task_id: "25475ede-ebd9-5c31-8c22-718e30acf8ac" ``` `docs/decisions/2026-09-22-brief-origin-publication.md`: FI grants fast-forward-only publication of `briefs/**` to `origin/main`; no force, no other refs; publication failure fails the run and leaves the day due. Supersedes the implicit grant wording in FI-WP-0004-T04. **Done when:** the decision is committed and cited by T01 and T04. **2026-09-22:** Done. Adds a single rebase-and-retry on non-fast-forward; it never merges or forces. Cited by the declaration and the activity-core proposal `8ee9a6ab`. ### T03 — Machine-readable source host list ```task id: FI-WP-0005-T03 status: done priority: high state_hub_task_id: "9b92d7f4-f4c8-5ce5-9367-462653515e90" ``` `docs/sources-allowlist.md` is prose with no hostnames. Derive an exact `host:443` list (lowercase, no wildcards, per sand-boxer rules) for axes A–D, kept beside the prose list and checked by a small test so the two do not drift. Keep it minimal. Egress is enforced by destination only, not by path, so every host is a trust decision. **Done when:** the list is committed with a test, and the host count and the rationale for each host are recorded. **2026-09-22:** Done. `docs/sources-egress.yaml` has 17 hosts covering axes A–D. `scripts/test_sources_egress.py` checks sand-boxer format, the 24-host cap and that each channel is named in the prose allowlist. A live check replaced redirecting hosts (docs.anthropic.com → platform.claude.com, lmarena.ai → arena.ai). openai.com and x.ai return 403 to plain clients, which is noted. ### T04 — activity-core handoff: grant v2 publication + generic due resolver ```task id: FI-WP-0005-T04 status: progress priority: high state_hub_task_id: "d679352f-8b0d-5ca5-9e42-4173ed87f48a" ``` Request (hub message to activity-core, not tasks registered here): - **Repository grant v2.** v1 fields plus `publication: {remote, ref, mode: fast-forward-only}`. Validated at definition sync and emission preflight. Close reconciliation requires matching `origin_sha` evidence when publication is granted; publication failure is a failed close, not a success. Needs an ADR amendment and agreement with rein-aharness (ADR-002). - **Published-artifact due resolver.** Parameters: repo, path template, ref, timezone, completion event type. Due is true unless the artifact exists on the remote ref *and* a matching event reports `pushed=true`. `fi_brief_status` becomes a thin alias, then is retired. **Done when:** activity-core acknowledges with its workplan id(s), and the agreed grant v2 schema revision is recorded here. **2026-09-22:** Proposal sent to activity-core (`8ee9a6ab`). Awaiting reply. ### T05 — glas-harness handoff: `harness.fi-research-brief@1.0.0` ```task id: FI-WP-0005-T05 status: progress priority: high state_hub_task_id: "e1d0bacd-b93d-50d5-b07d-e950e96443dc" ``` Request a profile: rein `rein-aharness`, unattended; bwrap sandbox with `network.egress` = model route + the T03 hosts, `default: deny`; a tool profile that can write only the granted paths and may publish only under a grant; model route and limits per T01; `operational_readiness` evidence; documented rollback pin. Blockers are the sand-boxer and Glas owner-auth items (SAND-WP-0015-T04, GLAS-WP-0012-T02). Track them, do not work around them. **Done when:** the profile exists at a pinned version with a positive readiness proof in a sandbox run. **2026-09-22:** Request sent to glas-harness (`c7f2df46`), including the host-install question. Awaiting reply. ### T06 — Retire the break-glass host timer ```task id: FI-WP-0005-T06 status: done priority: medium state_hub_task_id: "69abf6cf-95af-51b2-8874-120f30cb4b0a" ``` Delete `scripts/railiance-rhythm/systemd/*`, `install-on-railiance.sh` and `run-daily.sh` (keep `run-common.sh` only if it is still referenced). Replace `docs/recurrence-ops.md` and playbook references with a manual one-shot recovery command, valid until the legacy expiry, and the post-cutover rollback (T08). Remove the timer from railiance01. Rationale: the timer is a second scheduler outside activity-core. It runs the profile-absent legacy command with no grant, and its installer runs `enable --now`. After cutover it would bypass the profile and grant, and after the legacy expiry the command it calls stops working. A missed day costs little: due stays true, the verifier records the gap, and a catch-up brief closes it (FI-WP-0004-T05 precedent). **Done when:** the files are removed, the docs name the one-shot command and the profile-pin rollback, and the host has no FI timer. **2026-09-22:** Done. The earlier "not-found" check used the wrong unit names. `fi-research-brief-daily.{timer,service}` were installed but disabled and had never fired (`LastTriggerUSec` empty). They are now removed from `~/.config/systemd/user` and systemd has been reloaded; no FI brief unit remains. The whole `scripts/railiance-rhythm/` directory is deleted (`run-common.sh` had no other caller). `docs/recurrence-ops.md` documents the manual one-shot (`~/bin/rein-aharness-claim fi-research-brief --target-repo ... --date ...`) and the post-cutover rollback. ### T07 — Disabled canary definition ```task id: FI-WP-0005-T07 status: todo priority: high state_hub_task_id: "fd22b96d-39f0-53fd-9cdf-7bd29e758c54" ``` After T04 and T05: add a disabled, operator-triggered canary definition (pattern: activity-core `glas-profile-pilot`) carrying `harness_profile_ref`, grant v2 and the generic resolver, targeting a controlled date. Compare the output with the compatibility executor on the same inputs. Run `scripts/verify_brief_durability.py --require-date` on the canary day. **Done when:** one canary brief is on `origin/main` with grant, acceptance and `origin_sha` evidence reconciled by activity-core, and the comparison is recorded in `docs/evidence/`. ### T08 — Cutover, rollback proof, reply to rein ```task id: FI-WP-0005-T08 status: todo priority: high state_hub_task_id: "3bd365ad-7e9c-54cc-ad2b-e1cbbf525636" ``` Move `fi-daily-research-brief` to the profiled definition; ask rein-aharness to remove the FI label route and `fi_research_brief` compatibility path. Exercise rollback once: pin the previous profile version or revert the definition revision, and show that the due and evidence behaviour holds. Reply on thread `d0b45acb` with the definition revision, profile version, grant schema revision, and canary and rollback evidence. **Done when:** at least five consecutive weekday briefs have run on the profiled path, and rein confirms that FI no longer needs `AGENT_HARNESS_LEGACY_APPROACHES_UNTIL`. Target: before 2026-12-01. ## Risks - **Owner-auth blockers in sand-boxer and Glas** may not clear before December. Decision point on 2026-11-15: ask rein for a dated FI-only legacy extension. Do not fall back to shape A silently. - **Egress is enforced by host, not path.** A broad source host is a broad channel, so keep T03 minimal. - **Cross-repo contract change.** Grant v2 touches activity-core, rein-aharness and ADR-002; schedule slips there move T07. ## Out of scope - Changing brief content, template or axes - Reserve collection (FI-WP-0004 residuals: restore readback, scoped IAM key) - Other tenants' migrations (Binky etc.), except as consumers of the generic grant and resolver