state-hub/docs/evidence/2026-10-04-forge-qualifier-receiving.md
tegwick 3791e608ba
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Multi-Context Image / build-and-push (push) Successful in 29s
Verify offline scaffolds and preserve Forge qualifier receiving
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a10391-6355-7b41-b0fa-3e14e874f091
2026-10-04 02:32:37 +02:00

3.7 KiB

STATE-WP-0094-T04 — Forge qualifier receiving source validation

The committed source model already supports task decision_id, blocked_on, wait_until and flavor, and workplan flavor, flavor_promotion_reason and flavor_promoted_from. Forge receiving omitted them. The correction carries them through source derivation, projection JSON, dry-run diff, creation of a new workplan/task, creation of a task on an existing workplan, and updates of existing rows. It reuses the established closed flavor vocabulary and normalization.

Source authority is explicit: absent or YAML-null qualifiers/flavors clear stored values; quoted false clears needs_human. Existing identities are retained. Date-only values remain datetime.date in persistence and ISO dates in JSON. Bare/quoted timestamps, impossible dates, malformed qualifier YAML, invalid boolean/text qualifiers and unknown flavor values refuse derivation before receiving can update or cancel stored gates. The existing ForgeDeriveError API path reports the refusal. Origin and origin_ref are retained only in source; no schema or migration was added. Activity Core historical shared identities and frontmatter task parsing are outside this correction.

Validation and retained failed trial

Actual source validation command, run alone because the fixture database has a session-level schema lifecycle:

PYTHONDONTWRITEBYTECODE=1 .venv/bin/python -m pytest -p no:cacheprovider tests/test_forge_projection.py tests/test_forge_projection_qualifiers.py tests/test_work_record_projection_api.py tests/test_work_record_flavor.py tests/test_wait_kind.py -q

Final result: 130 passed in 41.68s. git diff --check passes. Ruff is unavailable in the repository venv and PATH; no lint result is claimed.

Earlier trial: 127 passed, two failed. Both failures exposed PyYAML's plain ValueError for the impossible bare date 2099-02-31. Catching YAML/ValueError as a whole-derivation refusal fixed the regression. Review before that run also found datetime accepted through isinstance(date); exact date acceptance and timestamp regressions corrected it. These are refinements of one trial, not extra successes.

The real API/PostgreSQL regression proves residual creation and exclusion from open views, promotion metadata, task creation on existing parents, qualifier updates, source null/absent clearing, unchanged UUIDs, normalized quoted false, independent repeat noop, and no stored-row changes after invalid source.

Tested SHA256 values:

  • api/services/forge_projection.py: d935fc6c9cb34c5d340ac09f02c929c4244a5fb2b2cf44796972083e98c98516
  • tests/test_forge_projection_qualifiers.py: a9c83c8b312f61e540d9f131c47c2adacabe219ae89644e480a9354668f27491

Boundaries and remaining live work

This is local source correctness, not a production receiving receipt. T05 owns current deployed revision, reviewed image/rollout/rollback preparation, separate production authorization and primary parity through normal immutable Forge reconciliation; direct C-41 repairs do not satisfy it. T05 also retains actual graph edge/freshness coverage. T03 retains supported runner selection, pickup deduplication and receipts; the execution launch-request consumer is retired. No deployment, schedule or human decision resolution occurred.

The historical CLI symptom remains distinguished. Today's CLI uses the same checker and deliberately turns warnings-only exit 2 into shell success. C-16 can skip writes, so successful process exit alone is not field parity. The prior Forge receiving omitted new fields on creation and ignored them on existing rows, including source removal; that does not prove it actively erased earlier correct qualifiers or explain every historical CLI/direct-run discrepancy.