Skip to content

Fix sharing.test.ts for discriminated union schema - #130

Merged
hotlong merged 2 commits into
copilot/release-new-version-please-workfrom
copilot/check-action-run-status
Jan 25, 2026
Merged

hotlong merged 2 commits into
copilot/release-new-version-please-workfrom
copilot/check-action-run-status

Conversation

Copilot AI commented Jan 25, 2026

Copy link
Copy Markdown
Contributor

Tests in sharing.test.ts were failing due to schema changes that introduced a discriminated union between CriteriaSharingRuleSchema and OwnerSharingRuleSchema.

Changes

Updated test data structure:

  • sharedWith: string → { type: ShareRecipientType, value: string }
  • criteria field renamed to condition (criteria-based rules)
  • Added ownedBy field (owner-based rules)
  • Removed 'manual' and 'guest' as valid rule types
  • Added 'full' as valid access level

Before:

const rule = {
  name: 'sales_access',
  object: 'opportunity',
  sharedWith: 'group_sales_team',
  criteria: 'status = "Open"',
};

After:

const rule = {
  name: 'sales_access',
  object: 'opportunity',
  type: 'criteria',
  condition: 'status = "Open"',
  sharedWith: { type: 'group', value: 'sales_team' },
};

All 24 sharing tests now pass.

Original prompt

引用: https://github.com/objectstack-ai/spec/actions/runs/21325211801/job/61381141562#step:8:1


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@vercel

vercel Bot commented Jan 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
spec Ready Ready Preview, Comment Jan 25, 2026 2:12am

Request Review

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Check action run status in GitHub CI Fix sharing.test.ts for discriminated union schema Jan 25, 2026
@hotlong
hotlong marked this pull request as ready for review January 25, 2026 02:13
Copilot AI review requested due to automatic review settings January 25, 2026 02:13
Copilot AI requested a review from hotlong January 25, 2026 02:13
@hotlong
hotlong merged commit f475c88 into copilot/release-new-version-please-work Jan 25, 2026
5 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the test suite in sharing.test.ts to align with schema changes that introduced a discriminated union between CriteriaSharingRuleSchema and OwnerSharingRuleSchema. The changes ensure all 24 tests pass with the new schema structure.

Changes:

  • Updated sharedWith from simple string to structured object with type and value fields
  • Renamed criteria field to condition for criteria-based rules
  • Added ownedBy field for owner-based rules
  • Removed 'manual' and 'guest' as valid rule types (now only 'owner' and 'criteria')
  • Added 'full' as a valid access level alongside 'read' and 'edit'

});

it('should accept manual sharing rule', () => {
it('should accept user-specific sharing rule', () => {

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name "should accept user-specific sharing rule" is misleading. This test is actually validating a criteria-based sharing rule that happens to share with a user recipient. The test name suggests it's testing a different rule type, but 'user-specific' is not a rule type in the schema - it's just using 'user' as a recipient type. Consider renaming to something like "should accept criteria rule with user recipient" to more accurately describe what's being tested.

Suggested change
it('should accept user-specific sharing rule', () => {
it('should accept criteria rule with user recipient', () => {

Copilot uses AI. Check for mistakes.
expect(rule.sharedWith.type).toBe('user');
});

it('should accept guest sharing rule', () => {

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name "should accept guest sharing rule" is misleading. After the schema changes, 'guest' is no longer a sharing rule type - it's now just a recipient type within the ShareRecipientType enum. This test is actually validating a criteria-based sharing rule that shares with guest recipients. Consider renaming to something like "should accept criteria rule with guest recipient" to accurately reflect the current schema structure.

Suggested change
it('should accept guest sharing rule', () => {
it('should accept criteria rule with guest recipient', () => {

Copilot uses AI. Check for mistakes.
Comment on lines 288 to 309
it('should reject sharing rule without required fields', () => {
expect(() => SharingRuleSchema.parse({
object: 'account',
sharedWith: 'group_id',
type: 'criteria',
condition: 'status = "Active"',
sharedWith: { type: 'group', value: 'group_id' },
})).toThrow();

expect(() => SharingRuleSchema.parse({
name: 'test_rule',
sharedWith: 'group_id',
type: 'criteria',
condition: 'status = "Active"',
sharedWith: { type: 'group', value: 'group_id' },
})).toThrow();

expect(() => SharingRuleSchema.parse({
name: 'test_rule',
object: 'account',
type: 'criteria',
condition: 'status = "Active"',
})).toThrow();
});

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test coverage for required fields should include validating that discriminated union requirements are enforced. Specifically, missing tests for:

  1. Owner-based rule without ownedBy field should be rejected
  2. Criteria-based rule without condition field should be rejected

These are critical validations for the discriminated union schema. Consider adding test cases like:

  • Testing that { name: 'test', object: 'account', type: 'owner', sharedWith: {...} } (missing ownedBy) throws an error
  • Testing that { name: 'test', object: 'account', type: 'criteria', sharedWith: {...} } (missing condition) throws an error

Copilot uses AI. Check for mistakes.
Comment on lines +196 to 220
it('should accept user-specific sharing rule', () => {
const rule = SharingRuleSchema.parse({
name: 'manual_share',
name: 'user_specific_share',
object: 'opportunity',
type: 'manual',
type: 'criteria',
condition: 'stage != "Closed Won"',
accessLevel: 'edit',
sharedWith: 'user_john_doe',
sharedWith: { type: 'user', value: 'john_doe' },
});

expect(rule.type).toBe('manual');
expect(rule.sharedWith.type).toBe('user');
});

it('should accept guest sharing rule', () => {
const rule = SharingRuleSchema.parse({
name: 'public_access',
object: 'knowledge_article',
type: 'guest',
type: 'criteria',
condition: 'published = true',
accessLevel: 'read',
sharedWith: 'guest_users',
sharedWith: { type: 'guest', value: 'guest_users' },
});

expect(rule.type).toBe('guest');
expect(rule.sharedWith.type).toBe('guest');
});

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests don't cover the 'role_and_subordinates' recipient type, which is defined in ShareRecipientType enum (sharing.zod.ts:41). Consider adding a test case to validate that sharing rules can use this recipient type, e.g., sharedWith: { type: 'role_and_subordinates', value: 'sales_manager' }

Copilot uses AI. Check for mistakes.
os-bill pushed a commit that referenced this pull request Sep 13, 2026
… shape and require `reference` on a `lookup` screen field

Maintainer ruling A′ (decision batch #130 item 1, 2026-09-13, verbatim
「同意」), applied across the five items it names.

1. Server-side enforcement at resume STAYS — `min_value` / `max_value`,
   both already in the ADR-0114 D2 catalog, no new error code.

2. The string gap closes. `validateScreenInputs` gains its own pass, BEFORE
   the bound: a present value for a `type: 'number'` screen field that is not
   a finite JSON number is refused with `invalid_type` — ⛔ never coerced.
   The bound pass compares numbers, so before this every non-number satisfied
   it by never reaching it (`"25"` under a `max` of 20 was conformant). The
   pin that recorded that silence is INVERTED in place, not deleted, so a
   later re-widening has to come back through it. Narrow in two directions on
   purpose: it keys off `type: 'number'` and not off the presence of a bound,
   and it is presence-conditioned exactly as the bound is.

3. `ScreenFieldConfigSchema` requires `reference` when `type` is `lookup`,
   via a `superRefine` that leaves `.shape` enumerable and the key set
   unmoved. This REVERSES the optionality the card first shipped; ADR-0078's
   own example of silently-inert metadata is a `lookup` with no `reference`,
   and a degraded shipped twin is not a reason to bend the contract to it.
   A stored bare lookup has NO lossless conversion — nothing in the metadata
   says which object the author meant — so it registers as an ADR-0087
   SEMANTIC entry (`screen-field-lookup-reference-required`, protocol 18),
   ⛔ never a D2 conversion that would have to invent a target. The entry is
   one file under `migrations/entries/semantic/`; `registry.ts` is its
   GENERATED projection (`gen:migration-registry`), never hand-merged.

4. The wording items, in every carrier: the bound's "re-checked when the
   submitted value is a number" qualifier is gone from the changeset, the
   flows guide, the generated node-config reference, both `.describe()`
   pairs, the `ScreenFieldSpec` doc block and the Studio designer form,
   because the qualifier is no longer true. `reference`'s requirement is
   stated wherever its optionality was.

5. `check:reference-carrier-shape` is green (exit 0): both `reference` sites
   this PR introduced reach their value through a name, which is the
   population the gate documents as unjudged. ⛔ No path ignore, and the
   `['a']` fixture still tests what it tested — it widened to four shapes,
   including the `{ object: 'x' }` carrier shape the gate exists for.

Also repaired, each falsified by the above rather than pre-existing:

- The changeset declared no break. It now carries `**BREAKING**` and the
  `<!-- adr-0087: registered screen-field-lookup-reference-required -->`
  disposition marker — a semantic entry with no declaration on the changeset
  is exactly what `check-adr-0087-registration` exists to notice. `minor`
  stays: the launch-window guard keeps breaks off `major` outside pre-mode.
- `ScreenInputIssue.code` enumerated `required` and `unknown_field` only and
  spoke of "the same two conditions". This PR put three more codes through
  that field.
- `ScreenFieldSpec.reference` claimed absence was "what every `lookup` screen
  field did before this key existed". It now states that the authoring schema
  refuses that shape, and why the WIRE type stays optional: a run suspended
  before the upgrade rehydrates a `ScreenSpec` stored under the old accept set.
- `api-surface/automation.json` and `export-origins/automation.json` were
  stale — the new exported refusal constant had never been propagated. Both
  regenerated with the repo's own generators; one additive line each.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants