Skip to content

feat(warpline): lifecycle facts on entity-assoc reverse-lookup + atomic reverify ingest#69

Closed
tachyon-beep wants to merge 3 commits into
mainfrom
feat/warpline-integration-p1
Closed

feat(warpline): lifecycle facts on entity-assoc reverse-lookup + atomic reverify ingest#69
tachyon-beep wants to merge 3 commits into
mainfrom
feat/warpline-integration-p1

Conversation

@tachyon-beep

Copy link
Copy Markdown
Collaborator

Part of warpline's P1 federation integration request (tracker: filigree-1299255fb5). This PR lands the two complete, low-risk pieces; the commit-anchor enhancement follows as a separate stacked PR.

Context

Warpline asked Filigree to support "if I touch X, what must I re-verify?" without crossing the authority boundary. After investigation, 2 of the 4 sub-deliverables were already built (consume reverify worklists; closed_at on the issue read). This PR closes the two real gaps that don't need a schema change, under the agreed contract Option B — warpline computes the "changed since claimed/closed" correlation; Filigree exposes the facts.

Changes

Added — issue lifecycle facts on the entity-association reverse-lookup (b-ii)

GET /api/entity-associations?entity_id=<sei> (and the MCP + data-layer reverse lookups) now enriches each binding row with the bound issue's claimed_at, closed_at, status, status_category, so warpline can correlate against its own changed-set in one round trip. closed_at is the proven-good signal ("issue closed at commit X"); Filigree exposes the resolution timestamp and stores no commit SHA — warpline maps timestamp→commit on its side.

  • Implemented as a separate EntityAssociationByEntityRow projection over a LEFT JOIN issues. The shared _row_to_entity_association mapper, the forward list_entity_associations, the add-response, and the governance closure gate are untouched and byte-identical.
  • LEFT (not INNER) JOIN keeps an orphaned binding (issue row absent — a contemplated state) in the result with null facts rather than dropping it.
  • Additive and Loomweave-safe: the Loomweave consumer (parse_entity_associations_response) has no serde deny_unknown_fields and is tested to ignore unknown fields, so the v1 consumer still parses v2. Contract fixture bumped to fixture_version 2.

Fixed — non-atomic reverify ingest (filigree-8340b79615)

warpline_worklist_ingest created the issue and bound its SEI in two separate transactions, so a non-retryable storage error on the bind left the issue FILED-but-UNBOUND — and the next ingest re-filed a duplicate (the loop-closure contract keys on the SEI binding). File + bind now commit in one transaction via create_issue's inline ADR-029 bind path. Regression test simulates a bind failure and asserts no orphan remains.

Boundary & acceptance

Filigree stays the work-state authority; nothing here calls warpline. With warpline absent, all flows are unchanged — these are pure read-field additions + an internal atomicity fix.

Tests

New: TestReverseLookupLifecycleFacts (5 cases incl. open/closed/claimed/orphan/forward-isolation), TestFileAndBindAtomicity. Gate green: ruff + ruff format --check + mypy src/filigree/ + full pytest (exit 0).

Follow-up (separate PR)

Commit-anchor (branch@sha at claim/close) — a v29 schema migration threaded through update_issue and the claim/close/reopen/release verbs, exposing claim_commit/close_commit so warpline correlates on commits, not clocks. Caller-supplied (Filigree stays out of git/CI). Tracked on filigree-1299255fb5.

🤖 Generated with Claude Code

tachyon-beep and others added 3 commits June 24, 2026 19:52
…p (warpline b-ii)

GET /api/entity-associations?entity_id=<sei> (and the MCP/db reverse lookup)
now enriches each binding row with the bound issue's claimed_at, closed_at,
status, and status_category, so warpline can correlate "changed since the
issue was claimed/closed" against its own changed-set in one round trip.
closed_at is the proven-good signal ("issue closed at commit X"); Filigree
exposes the resolution timestamp verbatim and stores no commit SHA — warpline
maps timestamp->commit on its side.

Implemented as a separate enriched projection (EntityAssociationByEntityRow)
via a LEFT JOIN to issues — the shared _row_to_entity_association mapper, the
forward list_entity_associations, the add-response, and governance.py are all
untouched and byte-identical. LEFT (not INNER) JOIN keeps an orphaned binding
(issue row absent) in the result with null facts rather than dropping it.

Additive and Loomweave-safe: the Loomweave consumer
(parse_entity_associations_response) has no serde deny_unknown_fields and is
tested to ignore unknown fields, so the v1 consumer still parses v2. Contract
fixture bumped to fixture_version 2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t-UNBOUND)

ingest_reverify_worklist created the issue and bound its SEI in two separate
@_in_immediate_tx transactions, so a non-retryable storage error on the bind
left the issue FILED-but-UNBOUND. Because the loop-closure contract keys on
the SEI association warpline reads back, the next ingest then saw the entity
as untracked and re-filed a duplicate.

Route the bind through create_issue's existing atomic inline-bind path
(entity_id / content_hash / entity_kind), so file+bind commit together in one
transaction; a bind failure rolls the whole item back. The warpline content
sentinel is preserved verbatim. Regression test simulates a bind failure and
asserts no orphaned issue remains.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fy ingest

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tachyon-beep

Copy link
Copy Markdown
Collaborator Author

Superseded by #70, which now targets main with the full set of commits (b-ii + atomicity fix + commit anchor). Consolidated to avoid fragmenting the work across stacked branches.

@tachyon-beep tachyon-beep deleted the feat/warpline-integration-p1 branch June 25, 2026 01:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant