Decide compute_domain_hint field-projector contract (re-add vs dot-path predicates vs per-blade flatteners) #3

Open
opened 2026-07-02 07:30:41 +00:00 by piersdd · 1 comment
piersdd commented 2026-07-02 07:30:41 +00:00 (Migrated from github.com)

Migrated from the vault DEVFU register by the DD-422 sweep (frozen-index entry [238], DEVFU-2026-05-24-stallari-mcp-helpers-field-projector-gap).

Context (register entry, verbatim)

DEVFU-2026-05-24-stallari-mcp-helpers-field-projector-gap — DD-338 Phase E.python Spec A redesigned compute_domain_hint's public API as 2-arg (record, patterns) with dot-path navigation built-in, dropping the field_projector: Callable callable that all 5 pre-consolidation blade copies carried. The gmail Spec B coding subagent discovered this is a real contract gap: gmail's record shape (payload.headers[name=From].value) has a list-with-predicate-then-field path that is NOT dot-path-addressable. Subagent's fix: keep gmail's local _gmail_field_projector + add a _flatten_gmail_record() helper that pre-projects records into a flat dict before passing to canonical compute_domain_hint. Verified all 4 other blades with domain_hint.py (ha, mastodon, tailscale, syncthing) ALSO carry their own _field_projector callables — likely will converge on the same _flatten_*_record pattern. The architectural question: should the canonical lib (a) re-add field_projector to the API as v0.2.0 (3-arg signature; pre-flatten approach moves back into the lib), (b) add native list-with-predicate dot-path syntax like headers[name=From].value (more expressive; more lib code), or (c) accept per-blade flatten helpers as the right boundary (blade-specific record shape stays per-blade; canonical lib stays minimal). Fix shape (decision-required): decide a/b/c after observing what the 3 in-flight Spec B clusters converge on. If all 4 blades use _flatten_*_record cleanly, (c) is the right call. If any blade resorts to ugly workarounds or duplicate logic, reconsider (a) or (b). Effort: architect 1h decision + (if a/b) ~2h lib + helper-package minor bump + 5-blade follow-up flip to remove _flatten_*_record helpers. Related: DD-338 Phase E.python; gmail PR h…

Acceptance criteria

  • Decision (a) re-add field_projector as 3-arg API / (b) native list-with-predicate dot-path syntax (headers[name=From].value) / (c) accept per-blade _flatten_*_record helpers — recorded after auditing what the Spec B blade clusters (gmail, ha, mastodon, tailscale, syncthing) converged on
  • If (a) or (b): lib updated with a minor version bump + 5-blade follow-up flip removing the _flatten_*_record helpers
  • If (c): the boundary is documented in the lib README/docstring so future blades follow it deliberately
  • Anchors DD-338 Phase E.python; gmail-blade-mcp PR #4 § 'Decisions where I diverged (a)'

Blocked by

None - can start immediately

Migrated from the vault DEVFU register by the DD-422 sweep (frozen-index entry [238], DEVFU-2026-05-24-stallari-mcp-helpers-field-projector-gap). ## Context (register entry, verbatim) **DEVFU-2026-05-24-stallari-mcp-helpers-field-projector-gap** — DD-338 Phase E.python Spec A redesigned `compute_domain_hint`'s public API as 2-arg `(record, patterns)` with dot-path navigation built-in, dropping the `field_projector: Callable` callable that all 5 pre-consolidation blade copies carried. The gmail Spec B coding subagent discovered this is a real contract gap: gmail's record shape (`payload.headers[name=From].value`) has a list-with-predicate-then-field path that is NOT dot-path-addressable. Subagent's fix: keep gmail's local `_gmail_field_projector` + add a `_flatten_gmail_record()` helper that pre-projects records into a flat dict before passing to canonical `compute_domain_hint`. Verified all 4 other blades with `domain_hint.py` (ha, mastodon, tailscale, syncthing) ALSO carry their own `_field_projector` callables — likely will converge on the same `_flatten_*_record` pattern. **The architectural question:** should the canonical lib (a) re-add `field_projector` to the API as v0.2.0 (3-arg signature; pre-flatten approach moves back into the lib), (b) add native list-with-predicate dot-path syntax like `headers[name=From].value` (more expressive; more lib code), or (c) accept per-blade flatten helpers as the right boundary (blade-specific record shape stays per-blade; canonical lib stays minimal). **Fix shape (decision-required):** decide a/b/c after observing what the 3 in-flight Spec B clusters converge on. If all 4 blades use `_flatten_*_record` cleanly, (c) is the right call. If any blade resorts to ugly workarounds or duplicate logic, reconsider (a) or (b). **Effort:** architect 1h decision + (if a/b) ~2h lib + helper-package minor bump + 5-blade follow-up flip to remove `_flatten_*_record` helpers. **Related:** [[DD-338]] Phase E.python; gmail PR h… ## Acceptance criteria - Decision (a) re-add `field_projector` as 3-arg API / (b) native list-with-predicate dot-path syntax (`headers[name=From].value`) / (c) accept per-blade `_flatten_*_record` helpers — recorded after auditing what the Spec B blade clusters (gmail, ha, mastodon, tailscale, syncthing) converged on - If (a) or (b): lib updated with a minor version bump + 5-blade follow-up flip removing the `_flatten_*_record` helpers - If (c): the boundary is documented in the lib README/docstring so future blades follow it deliberately - Anchors [[DD-338]] Phase E.python; gmail-blade-mcp PR #4 § 'Decisions where I diverged (a)' ## Blocked by None - can start immediately
piersdd commented 2026-07-16 12:18:04 +00:00 (Migrated from github.com)

Decision brief (AI triage, 2026-07-16) — the convergence evidence is now in, and it did NOT converge on (c).

Current state across the 5 blades (checked live in local checkouts):

  • gmail: _flatten_gmail_record() pre-flatten + local _gmail_field_projector (the (c) pattern).
  • syncthing: retired its projector; uses the canonical lib's dot-path resolution natively (pure 2-arg).
  • mastodon: still calls compute_domain_hint(rec, _PATTERNS, _field_projector) — a 3-arg call, i.e. a local/duplicate compute_domain_hint, not the canonical 2-arg lib.
  • tailscale: keeps a field_projector= default parameter in its own wrapper (_tailscale_field_projector).
  • home-assistant: local _field_projector closure-captured.

That's 4 of 5 blades carrying duplicate projector logic — the "ugly workarounds or duplicate logic" trigger the issue named for reconsidering (a).

Lean: (a) — re-add field_projector as an optional 3rd argument in stallari-mcp-helpers v0.2.0 (default = built-in dot-path, so syncthing-style callers are untouched), then delete the per-blade copies in a follow-up sweep. (b) list-predicate dot-path syntax is more lib for one gmail-shaped case; (c) is empirically not what the blades did.

Your move: confirm (a) and I'll queue the v0.2.0 change + the 4-blade cleanup sweep as agent work.

**Decision brief (AI triage, 2026-07-16) — the convergence evidence is now in, and it did NOT converge on (c).** Current state across the 5 blades (checked live in local checkouts): - **gmail**: `_flatten_gmail_record()` pre-flatten + local `_gmail_field_projector` (the (c) pattern). - **syncthing**: retired its projector; uses the canonical lib's dot-path resolution natively (pure 2-arg). - **mastodon**: still calls `compute_domain_hint(rec, _PATTERNS, _field_projector)` — a **3-arg call**, i.e. a local/duplicate `compute_domain_hint`, not the canonical 2-arg lib. - **tailscale**: keeps a `field_projector=` default parameter in its own wrapper (`_tailscale_field_projector`). - **home-assistant**: local `_field_projector` closure-captured. That's 4 of 5 blades carrying duplicate projector logic — the "ugly workarounds or duplicate logic" trigger the issue named for reconsidering (a). **Lean: (a)** — re-add `field_projector` as an **optional 3rd argument** in stallari-mcp-helpers v0.2.0 (default = built-in dot-path, so syncthing-style callers are untouched), then delete the per-blade copies in a follow-up sweep. (b) list-predicate dot-path syntax is more lib for one gmail-shaped case; (c) is empirically not what the blades did. **Your move:** confirm (a) and I'll queue the v0.2.0 change + the 4-blade cleanup sweep as agent work.
This discussion has been locked. Commenting is limited to contributors.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Stallari/mcp-helpers#3
No description provided.