Skip to content

feat(company-monitoring): add identity_unresolved coverage state - #7063

Open
yzxcj797 wants to merge 10 commits into
koala73:mainfrom
yzxcj797:feat/identity-unresolved-coverage-7044
Open

feat(company-monitoring): add identity_unresolved coverage state#7063
yzxcj797 wants to merge 10 commits into
koala73:mainfrom
yzxcj797:feat/identity-unresolved-coverage-7044

Conversation

@yzxcj797

Copy link
Copy Markdown
Contributor

Implements #7044.

What

A distinct coverage state for a company with no independent identity binding. Such a company cannot be scanned — no provider query can be safely attributed to it — so it must never read as a quiet result; the #6002 stop conditions prohibit the false quiet.

Both sources of truth

  • CompanyCoverageState proto enum: COMPANY_COVERAGE_STATE_IDENTITY_UNRESOLVED = 7 (new number, nothing renumbered), carried into the generated client/server unions and the generated request-validation pattern.
  • convex/schema.ts: coverageState: v.optional(v.union(v.literal("awaiting_first_scan"), v.literal("identity_unresolved"))) — absent still means resolved-and-scanned, with observationState carrying the result.

Transitions (non-overlapping, per the issue)

  • Set when identity resolution fails — an X identity observation that lands demoted (family conflict, account change, or expiry) marks the company identity_unresolved (applyXIdentitiespatchCompanyCoverageForIdentity).
  • Cleared when a binding is verified — an authoritative identity resolves the company (coverage back to undefined).
  • Reinstated on demotion — the official_link_lostauthority_lost path (a held binding whose domain claim expired or lost authority) re-marks the company identity_unresolved, so a company that held a binding and lost it does not silently read as quiet.
  • snapshotGeneration: every coverage flip advances the company row's own snapshotGeneration — the freshness signal company-scoped reads compare against — encoded in a test rather than assumed (the acceptance criterion's exact ask).

Published surfaces

  • shared/company-monitoring-contract.ts: the state joins the coverage union, the validator set, and both COVERAGE_STATE_BY_INPUT spellings; assertCoverageObservation still refuses identity_unresolved + no_events_observed (the never-quiet guarantee), now pinned by an explicit test.
  • scripts/openapi-inject-company-monitoring-contract.mjs publishes the state with a description stating it is not a quiet result; the three committed OpenAPI artifacts are regenerated through the injector.

Tests

  • companyMonitoringXIngestion.test.ts: demotion reinstates identity_unresolved with the generation bump (asserting the before/after delta), and an authoritative identity clears a previously-unresolved company — 26/26 green (24 existing untouched).
  • tests/company-monitoring-contract.test.mts: the state is valid with unknown observation but can never carry no_events_observed; both filter spellings normalize — 30/30.
  • tests/company-monitoring-openapi-contract.test.mjs: 7/7 after injector regeneration.
  • Full convex suite: 1293/1293. tsc --noEmit clean, biome clean on all touched files.

Local-environment note: the OpenAPI injector's YAML patcher does exact line matches, so a Windows CRLF checkout makes it fail; the three target artifacts were LF-normalized before running it (its own idempotency test then passes). CI on LF checkouts is unaffected.

A company with no independent identity binding cannot be scanned — no
provider query can be safely attributed to it — so it must never read
as a quiet result. Reporting such a company as quiet is the false
quiet the koala73#6002 stop conditions prohibit (koala73#7044).

Both sources of truth carry the new state: the
CompanyCoverageState proto enum (new number 7, no renumbering) with
the generated client/server unions and the generated request
validation pattern, and the convex coverageState union
(awaiting_first_scan | identity_unresolved; absent still means
resolved-and-scanned, with observationState carrying the result).

Transitions, with the non-overlap semantics from the issue:

- set when identity resolution fails: an X identity observation that
  lands demoted (conflict, account change, or expiry) marks the
  company identity_unresolved;
- cleared when a binding is verified: an authoritative identity
  resolves the company (coverageState back to undefined);
- reinstated on demotion: the official_link_lost / authority_lost
  path that fires when a held binding expires or loses its domain
  claim re-marks the company identity_unresolved, so a company that
  held a binding and lost it does not silently read as quiet;
- every coverage flip advances the company row's own
  snapshotGeneration — that is the freshness signal company-scoped
  reads compare against, so a flip without the bump would stay
  invisible to snapshot-gated consumers (encoded in a test).

The shared coverage contract accepts the state in both spellings,
the OpenAPI injector publishes it with a description stating it is
not a quiet result, and assertCoverageObservation keeps refusing it
as a carrier of no_events_observed — the never-quiet guarantee is
pinned by tests on the contract and on the demotion transition.
@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

@yzxcj797 is attempting to deploy a commit to the World Monitor Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the trust:safe Brin: contributor trust score safe label Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trust:safe Brin: contributor trust score safe

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants