Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(fields): surface live/liveReason on list-fields

merged#2718CedarCopilot

CedarCopilot wants to merge 0 commits into docs/cedar-authoring-skill-fixes from feat/list-fields-live-flag

Not deployedTimeline and evidence
  1. Opened
    Sep 7, 2026, 10:26 AM
  2. Merged
    Sep 7, 2026, 10:47 AM
  3. Not deployed

    Not deployed

    Pending

Libra has no production signal for this change yet because it has not deployed. Libra checks hourly for 3 days after each deploy.

Summary

Stacks on #2717 (docs/cedar-authoring-skill-fixes) , that PR documents this feature in using-and-configuring-extracted-fields.md before this implements it; this PR is the code that makes the doc accurate.

A field can pass every other authoring check (right scope, not owned, not approval-gated) and still never actually be kept current if no crm-updater the AOP's playbook resolves to will ever write it. list-fields now returns live: boolean and liveReason: string per field:

  • a built-in field is always live
  • a background (taxonomy) field is never live , that extraction path is separate from crm-updater and confirmed not continuous today
  • a custom field is live only when its own scope matches the AOP's actually-resolved crm-updater scope; a linked field's two rows (one org, one user) naturally resolve to exactly one live copy for free

Deliberately reimplements the crm-updater scope query with this file's own db.select() style rather than calling the existing resolveCrmUpdaterScope directly , that function opens its own DB connection and reads via db.query.*, neither of which this file's tests mock , while delegating the actual decision to the shared pure pickCrmUpdaterScope, so there's still exactly one place that logic lives.

A real bug caught by thermo-review before this ever reached a PR

The MCP tool's output schema (ListFieldsDataSchema) didn't declare the two new fields. @mastra/core's Tool.execute wrapper runs schema.safeParse(output) and returns the parsed result, not the raw object , a bare z.object() silently strips undeclared keys on parse. Both new fields would have been dropped at the MCP boundary despite computing correctly in the service layer and passing every test and the typecheck (since neither crosses the schema boundary). Fixed by declaring both fields on the schema, with a comment naming the exact framework behavior.

Libra's review of that fix flagged a second real gap: none of the existing tests for this tool actually exercise the real safeParse path , configTool.test.ts and its siblings mock createTool to a pass-through no-op specifically to test dispatch without a DB, which also means they never run real schema validation. Added a small, targeted test calling ConfigReadOutputSchema.safeParse() directly (the same call the real wrapper makes) proving both that the fields survive parsing and that omitting one is actually rejected.

Test plan

  • pnpm exec vitest run src/services/aop/__tests__/list-fields.test.ts src/mastra/tools/config/__tests__/ , 146/146 pass
  • pnpm run types (full @zero/server) , clean
  • pnpm deps:check , no dependency violations
  • thermo-review run against the diff (full output in session notes) , one šŸ”“-class finding (the schema-stripping bug above), fixed and re-verified before opening this PR

šŸ¤– Generated with Claude Code

https://claude.ai/code/session_01F4mjBtjYZyxnVvLQpehDSb

Greptile Summary

This PR exposes field liveness through the list-fields service and MCP output schema.

  • Resolves the CRM-updater scope from compiled playbook references.
  • Reports a boolean and explanatory reason for built-in, background, and custom fields.
  • Adds service-level liveness coverage and a direct schema-boundary regression test.

Confidence Score: 4/5

The liveness behavior appears correct, but the explicit repository no-cast requirement must be satisfied before merging.

No behavioral or security failure remains after checking resolver parity, producer compatibility, and updater semantics; the sole accepted finding is a concrete repository-rule violation in newly added type assertions.

Files Needing Attention: apps/server/src/services/aop/list-fields.ts; apps/server/src/mastra/tools/config/tests/config-read-output-schema.test.ts

Important Files Changed

FilenameOverview
apps
Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/src/mastra/tools/config/__tests__/config-read-output-schema.test.tsno production surface mapped
  • apps/server/src/mastra/tools/config/config-read-tool.tsno production surface mapped
  • apps/server/src/services/aop/__tests__/list-fields.test.tsno production surface mapped
  • apps/server/src/services/aop/list-fields.tsno production surface mapped