Require published FI brief evidence before clearing daily due
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 32s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a09cbd-43c1-79f3-809e-1ee97b40b64d
This commit is contained in:
tegwick 2026-09-14 00:44:58 +02:00
parent 039010f2b8
commit 289aff3dbf
6 changed files with 110 additions and 22 deletions

View file

@ -34,7 +34,7 @@
| workplan | ACTIVITY-WP-0028 | finished | — | workplans/ACTIVITY-WP-0028-activity-review-cli.md |
| workplan | ACTIVITY-WP-0029 | finished | — | workplans/ACTIVITY-WP-0029-hub-port-alignment.md |
| workplan | ACTIVITY-WP-0030 | finished | — | workplans/ACTIVITY-WP-0030-daily-sbom-catchup.md |
| workplan | ACTIVITY-WP-0031 | active | — | workplans/ACTIVITY-WP-0031-production-execution-reliability-cleanup.md |
| workplan | ACTIVITY-WP-0031 | finished | — | workplans/ACTIVITY-WP-0031-production-execution-reliability-cleanup.md |
| workplan | ACTIVITY-WP-0032 | active | — | workplans/ACTIVITY-WP-0032-glas-profile-execution-contract.md |
| workplan | ACTIVITY-WP-0033 | finished | — | workplans/ACTIVITY-WP-0033-sbom-catchup-retry-boundary.md |
| workplan | ACTIVITY-WP-0034 | finished | — | workplans/ACTIVITY-WP-0034-sbom-controlled-source-reference.md |
@ -44,6 +44,7 @@
| workplan | ACTIVITY-WP-ADHOC-2026-06-01 | finished | — | workplans/ADHOC-2026-06-01.md |
| workplan | ACTIVITY-WP-ADHOC-2026-08-20 | finished | — | workplans/ADHOC-2026-08-20.md |
| workplan | ACTIVITY-WP-ADHOC-2026-08-23 | finished | — | workplans/ADHOC-2026-08-23.md |
| workplan | ACTIVITY-WP-ADHOC-2026-09-14 | finished | — | workplans/ADHOC-2026-09-14.md |
| workplan | custodian-WP-0001 | done | — | workplans/custodian-WP-0001-temporal-backbone.md |
| workplan | custodian-WP-0002 | done | — | workplans/custodian-WP-0002-triggers-ops.md |
| workplan | custodian-WP-0003a | done | — | workplans/custodian-WP-0003a-event-bridge-model-rules-registry.md |
@ -199,7 +200,7 @@
| task | ACTIVITY-WP-0031-T02 | done | — | workplans/ACTIVITY-WP-0031-production-execution-reliability-cleanup.md |
| task | ACTIVITY-WP-0031-T03 | done | — | workplans/ACTIVITY-WP-0031-production-execution-reliability-cleanup.md |
| task | ACTIVITY-WP-0031-T04 | done | — | workplans/ACTIVITY-WP-0031-production-execution-reliability-cleanup.md |
| task | ACTIVITY-WP-0031-T05 | wait | — | workplans/ACTIVITY-WP-0031-production-execution-reliability-cleanup.md |
| task | ACTIVITY-WP-0031-T05 | done | — | workplans/ACTIVITY-WP-0031-production-execution-reliability-cleanup.md |
| task | ACTIVITY-WP-0032-T01 | done | — | workplans/ACTIVITY-WP-0032-glas-profile-execution-contract.md |
| task | ACTIVITY-WP-0032-T02 | done | — | workplans/ACTIVITY-WP-0032-glas-profile-execution-contract.md |
| task | ACTIVITY-WP-0032-T03 | done | — | workplans/ACTIVITY-WP-0032-glas-profile-execution-contract.md |
@ -231,6 +232,8 @@
| task | ACTIVITY-WP-ADHOC-2026-06-01-T03 | done | — | workplans/ADHOC-2026-06-01.md |
| task | ACTIVITY-WP-ADHOC-2026-08-20-T01 | done | — | workplans/ADHOC-2026-08-20.md |
| task | ACTIVITY-WP-ADHOC-2026-08-23-T01 | done | — | workplans/ADHOC-2026-08-23.md |
| task | ACTIVITY-WP-ADHOC-2026-09-14-T01 | done | — | workplans/ADHOC-2026-09-14.md |
| task | ACTIVITY-WP-ADHOC-2026-09-14-T02 | done | — | workplans/ADHOC-2026-09-14.md |
| task | T01 | done | — | workplans/custodian-WP-0001-temporal-backbone.md |
| task | T02 | done | — | workplans/custodian-WP-0001-temporal-backbone.md |
| task | T03 | done | — | workplans/custodian-WP-0001-temporal-backbone.md |

View file

@ -1202,7 +1202,7 @@ spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: activity-core:railiance01-prod
image: activity-core:fi-publication-20260914
imagePullPolicy: Never
command: ["python", "-m", "alembic", "upgrade", "head"]
envFrom:
@ -1230,7 +1230,7 @@ spec:
restartPolicy: OnFailure
containers:
- name: sync
image: activity-core:railiance01-prod
image: activity-core:fi-publication-20260914
imagePullPolicy: Never
command:
- sh
@ -1287,7 +1287,7 @@ spec:
spec:
containers:
- name: api
image: activity-core:railiance01-prod
image: activity-core:fi-publication-20260914
imagePullPolicy: Never
command: ["uvicorn", "activity_core.api:app", "--host", "0.0.0.0", "--port", "8010"]
ports:
@ -1363,7 +1363,7 @@ spec:
fsGroup: 1000
containers:
- name: worker
image: activity-core:railiance01-prod
image: activity-core:fi-publication-20260914
imagePullPolicy: Never
command: ["python", "-m", "activity_core.worker"]
ports:
@ -1458,7 +1458,7 @@ spec:
spec:
containers:
- name: event-router
image: activity-core:railiance01-prod
image: activity-core:fi-publication-20260914
imagePullPolicy: Never
command: ["python", "-m", "activity_core.event_router"]
envFrom:

View file

@ -43,8 +43,9 @@ from __future__ import annotations
import json
import logging
import os
import re
import time
from datetime import datetime, timezone
from datetime import date, datetime, timezone
from typing import Any
import httpx
@ -655,10 +656,10 @@ def _fi_brief_status(params: dict[str, Any]) -> dict[str, Any]:
Params: repo (default "freedom-intelligence"), timezone (IANA name,
default Europe/Berlin "today" is evaluated in this zone).
due is true when no progress event with event_type=fi_daily_brief and
detail.repo matching the target repo exists for today. Executing sessions
must post that event on completion (see freedom-intelligence
docs/daily-brief-playbook.md).
Only a pushed completion with an immutable origin SHA and the canonical
brief path can clear due. Compare detail.date, not event arrival date, so
late delivery of yesterday's brief cannot suppress today's work. Git tree
verification is performed by freedom-intelligence's durability audit.
"""
repo = str(params.get("repo") or _FI_BRIEF_DEFAULT_REPO)
kind = str(params.get("kind") or "daily_brief")
@ -670,15 +671,23 @@ def _fi_brief_status(params: dict[str, Any]) -> dict[str, Any]:
today = now_local.date()
events = _binky_progress_events(_FI_BRIEF_EVENT_TYPE, repo)
timestamps = [
ts
for ts in (
_parse_progress_timestamp(item.get("created_at")) for item in events
)
if ts > datetime.min.replace(tzinfo=timezone.utc)
]
last_run = max(timestamps, default=None)
due = last_run is None or last_run.astimezone(tz).date() != today
valid = []
for event in events:
detail = _progress_detail(event)
day = detail.get("date")
try:
parsed_day = date.fromisoformat(day)
except (ValueError, TypeError):
continue
if (parsed_day.isoformat() != day or detail.get("repo") != repo
or detail.get("pushed") is not True
or not re.fullmatch(r"[0-9a-f]{40}", str(detail.get("origin_sha", "")))
or detail.get("path") != f"briefs/{day[:4]}/{day[5:7]}/{day}.md"):
continue
valid.append(event)
timestamps = [_parse_progress_timestamp(event.get("created_at")) for event in valid]
last_run = max((ts for ts in timestamps if ts > datetime.min.replace(tzinfo=timezone.utc)), default=None)
due = not any(_progress_detail(event)["date"] == today.isoformat() for event in valid)
return {
"items": [

View file

@ -1150,7 +1150,9 @@ def test_fi_brief_status_not_due_after_todays_run(monkeypatch) -> None:
{
"event_type": "fi_daily_brief",
"created_at": "2026-07-17T05:30:00+00:00",
"detail": {"repo": "freedom-intelligence"},
"detail": {"repo": "freedom-intelligence", "date": "2026-07-17",
"path": "briefs/2026/07/2026-07-17.md",
"pushed": True, "origin_sha": "a" * 40},
}
]
},
@ -1195,3 +1197,27 @@ def test_fi_brief_status_unknown_kind(monkeypatch) -> None:
assert result["items"] == []
assert "unknown kind" in result["error"]
@pytest.mark.parametrize("override", [
{"pushed": False}, {"pushed": "true"}, {"origin_sha": ""},
{"origin_sha": "main"}, {"path": "briefs/wrong.md"}, {"date": "bad-date"},
{"repo": None},
])
def test_fi_brief_rejects_unpublished_or_malformed_completion(monkeypatch, override):
detail = dict(repo="freedom-intelligence", date="2026-07-17",
path="briefs/2026/07/2026-07-17.md", pushed=True, origin_sha="a" * 40)
detail.update(override)
_binky_resolver_env(monkeypatch, {"fi_daily_brief": [dict(
event_type="fi_daily_brief", created_at="2026-07-17T05:30:00+00:00", detail=detail)]})
result = StateHubContextResolver().resolve("fi_brief_status", None, {"repo": "freedom-intelligence"})
assert result["items"][0]["due"] is True
def test_fi_brief_late_yesterday_event_does_not_clear_today(monkeypatch):
detail = dict(repo="freedom-intelligence", date="2026-07-16",
path="briefs/2026/07/2026-07-16.md", pushed=True, origin_sha="a" * 40)
_binky_resolver_env(monkeypatch, {"fi_daily_brief": [dict(
event_type="fi_daily_brief", created_at="2026-07-17T05:30:00+00:00", detail=detail)]})
result = StateHubContextResolver().resolve("fi_brief_status", None, {"repo": "freedom-intelligence"})
assert result["items"][0]["due"] is True

View file

@ -9,6 +9,7 @@ owner: custodian
topic_slug: custodian
created: "2026-06-01"
updated: "2026-06-03"
state_hub_workstream_id: "4b5abcd1-e1a2-5840-a852-2d14c867c5f8"
---
# ACTIVITY-WP-ADHOC-2026-06-01 — activity-core opportunistic fixes

View file

@ -0,0 +1,49 @@
---
id: ACTIVITY-WP-ADHOC-2026-09-14
type: workplan
title: Require publication evidence for the FI daily due gate
domain: infotech
repo: activity-core
status: finished
owner: codex
created: "2026-09-14"
updated: "2026-09-14"
state_hub_workstream_id: "5434dcd8-f1a4-5869-a306-dfa7eaff5885"
---
## Reject unpublished and misdated FI completion events
```task
id: ACTIVITY-WP-ADHOC-2026-09-14-T01
status: done
priority: high
state_hub_task_id: "78b343f0-4059-5df6-b4e3-2187a97dccef"
```
Only pushed=true, full origin SHA and canonical date/path can clear due.
Use detail.date rather than created_at, so late delivery cannot suppress the
next day. The FI verifier checks actual origin objects. Resolver suite: 47
passed, including invalid publication and delayed-delivery regression cases.
## Deploy and verify the production resolver
```task
id: ACTIVITY-WP-ADHOC-2026-09-14-T02
status: done
priority: high
state_hub_task_id: "0d1d729c-ce48-5784-99cc-dea4a5e5b587"
```
Use image activity-core:fi-publication-20260914, layered over the exact live
baseline (container image ID sha256:e6e9f0171e36ce0f50a970435ea55f10d428f1743050d1629a94ff4fd19cec37).
The baseline resolver module was byte-identical to pre-change repo HEAD;
only the tested module is replaced. No schema or other application changes.
Keep the remote checkout's unrelated dirty files untouched.
Roll API, worker and event-router; verify rollout, live due=true for the
September 14 brief, and Temporal next action 05:30 UTC / 07:30 Berlin.
Future run completion must be proven separately by FI's --require-date audit.
Live verification: API, worker and event-router run the new image and are ready.
API imports the patched resolver; September 14 remains due until publication.
The three image smoke cases (unpublished, published, late delivery) passed.