Skip to content

fix(update_project): numeric field values now correctly infer NUMBER type - #49073

Merged
pelikhan merged 3 commits into
mainfrom
copilot/update-project-numeric-fields-inference
Jul 30, 2026
Merged

fix(update_project): numeric field values now correctly infer NUMBER type#49073
pelikhan merged 3 commits into
mainfrom
copilot/update-project-numeric-fields-inference

Conversation

Copilot AI commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

inferFieldDataType had no NUMBER branch — finite JS numbers fell through to SINGLE_SELECT. For an existing NUMBER field this produced a spurious type-mismatch warning; for a missing field it created the wrong type entirely.

Changes

update_project.cjs

  • inferFieldDataType: returns "NUMBER" for typeof value === "number" && Number.isFinite(value) (handles zero, negatives, floats; excludes NaN/Infinity which still fall to SINGLE_SELECT). JSDoc return type updated.
  • applyFieldUpdates: adds isNumberField flag and a new else if (isNumberField) creation branch that calls createProjectV2Field with dataType: "NUMBER" when the field is missing.

update_project.test.cjs

  • Updated existing inferFieldDataType test that asserted SINGLE_SELECT for a numeric value.
  • Added unit tests for zero, negative, and non-finite values.
  • Added integration tests: create missing NUMBER field, set zero, and verify no spurious warning on an existing NUMBER field.

Example

{
  "type": "update_project",
  "fields": { "Comment Count": 30 }
}

Previously logged Field type mismatch for "Comment Count": Expected SINGLE_SELECT but found NUMBER. Now resolves correctly with no warning.

…andler

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix numeric fields being inferred as SINGLE_SELECT in update_project fix(update_project): numeric field values now correctly infer NUMBER type Jul 30, 2026
Copilot AI requested a review from pelikhan July 30, 2026 06:48
@pelikhan
pelikhan marked this pull request as ready for review July 30, 2026 07:02
Copilot AI review requested due to automatic review settings July 30, 2026 07:02
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories (0 additions detected in default business dirs).

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

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

Fixes numeric project-field inference and creation.

Changes:

  • Infers finite numbers as NUMBER.
  • Creates missing number fields.
  • Adds numeric-value tests.
Show a summary per file
File Description
actions/setup/js/update_project.cjs Adds NUMBER inference and creation.
actions/setup/js/update_project.test.cjs Tests numeric inference and updates.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread actions/setup/js/update_project.cjs Outdated
core.warning(`Failed to create field "${fieldName}": ${getErrorMessage(createError)}`);
continue;
}
} else if (isNumberField) {
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Warning

threat detection engine error
The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding.

Details

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@github-actions github-actions Bot 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.

The changes correctly add NUMBER type inference and field creation for finite numeric values. Logic is sound, tests cover zero, negative, and Infinity edge cases, and the checkFieldTypeMismatch function handles NUMBER via exact-type comparison without any special-casing needed. No issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 18.1 AIC · ⌖ 5.41 AIC · ⊞ 5.3K

@github-actions github-actions Bot 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.

REQUEST_CHANGES — the fix reintroduces a mirror-image regression: existing SINGLE_SELECT fields holding numeric-looking option values will now get spurious "Field type mismatch" warnings on every run.

💡 Themes
  1. Correctness regression (high, blocking): inferFieldDataType now unconditionally maps any finite number to NUMBER, with no way for an existing SINGLE_SELECT field with numeric option labels to avoid a new spurious type-mismatch warning — the exact class of bug this PR claims to fix, just flipped to the opposite field type. No test covers this scenario.
  2. Maintainability (medium): the new NUMBER field-creation GraphQL block duplicates the adjacent DATE/TEXT creation blocks almost verbatim; a shared helper would reduce triplicated maintenance and the risk of divergent fixes (already visible here, since the new dataType fragment field wasn't added to the other two branches).
  3. Test coverage for the new happy paths (NUMBER creation, zero value, existing NUMBER field) is solid, but the SINGLE_SELECT-with-numeric-value regression scenario is untested and should be added regardless of how the fix is implemented.

🔎 Code quality review by PR Code Quality Reviewer · auto · 64.8 AIC · ⌖ 4.79 AIC · ⊞ 7.8K
Comment /review to run again

Comment on lines 439 to +442
if (isTextField) {
return "TEXT";
}
if (typeof fieldValue === "number" && Number.isFinite(fieldValue)) {

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.

Any numeric YAML value is now inferred as NUMBER, which is a breaking regression for pre-existing SINGLE_SELECT fields that legitimately hold numeric-looking option labels.

💡 Details

Before this PR, any finite number fell through to SINGLE_SELECT. Now inferFieldDataType unconditionally returns NUMBER for typeof value === "number" && Number.isFinite(value), with no way to opt back into SINGLE_SELECT for numeric values.

Consider a workflow with an existing SINGLE_SELECT field named Priority whose options are 1, 2, 3 (numeric labels), configured with priority: 2. Previously this worked with no warning. After this change, expectedDataType becomes NUMBER, and checkFieldTypeMismatch(fieldName, field, "NUMBER") will fire a Field type mismatch for "Priority": Expected NUMBER but found SINGLE_SELECT warning on every single run, even though the field type is correct and intentional.

The fix in the PR description is scoped to "missing field creates the wrong type" and "existing NUMBER field produces spurious warning" — but it introduces the mirror-image bug for existing SINGLE_SELECT fields with numeric values, which isn't covered by any new test.

Suggested fix: only infer NUMBER when there's no existing field, or when the existing field's dataType is unknown — i.e. pass the existing field (or its dataType) into inferFieldDataType and prefer the already-established type over re-inferring from the value when a field already exists.

Comment thread actions/setup/js/update_project.cjs Outdated
Comment on lines +572 to +597
} else if (isNumberField) {
try {
field = (
await github.graphql(
`mutation($projectId: ID!, $name: String!, $dataType: ProjectV2CustomFieldType!) {
createProjectV2Field(input: {
projectId: $projectId,
name: $name,
dataType: $dataType
}) {
projectV2Field {
... on ProjectV2Field {
id
name
dataType
}
}
}
}`,
{ projectId, name: normalizedFieldName, dataType: "NUMBER" }
)
).createProjectV2Field.projectV2Field;
} catch (createError) {
core.warning(`Failed to create number field "${fieldName}": ${getErrorMessage(createError)}`);
continue;
}

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.

This NUMBER field-creation branch is a near copy-paste of the adjacent DATE-field mutation (differs only in dataType and warning text), tripling the maintenance surface for the same GraphQL call.

💡 Details

The DATE branch (lines ~514-537), this NUMBER branch (~573-597), and the TEXT branch (~544-571) all issue functionally identical createProjectV2Field mutations that differ only in the dataType argument, the response fragment selected, and the warning message on failure. Any future fix to the mutation shape (e.g. adding a new field to select, changing error handling, adding retries) now needs to be applied in three places, and this PR already demonstrates the risk: the fragment ... on ProjectV2Field { id name dataType } was added here but not to the TEXT or DATE branches, so they remain inconsistent in what they request back.

Suggested fix: extract a shared createSimpleProjectField(github, projectId, name, dataType, extraFragment) helper used by DATE/TEXT/NUMBER creation, keeping only the SINGLE_SELECT case (which needs options) separate.

@github-actions github-actions Bot 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.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — approving with minor suggestions.

📋 Key Themes & Highlights

Key Themes

  • Root cause properly fixed: The missing NUMBER branch in inferFieldDataType is the real issue and it's addressed directly — not just the symptom.
  • Good edge case coverage: Zero, negative, and Infinity values are all tested. One small gap: NaN lacks a dedicated unit test (see inline comment).
  • GraphQL fragment consistency: The new NUMBER field creation mutation uses only the ProjectV2Field fragment (correct), but a brief comment would clarify intent vs. the TEXT branch's union-type pattern.

Positive Highlights

  • Number.isFinite correctly excludes both NaN and ±Infinity — handles the tricky JS numeric edge cases right
  • ✅ Integration tests cover the three key scenarios: create-missing, set-zero, no-spurious-warning on existing field
  • ✅ JSDoc return type updated to include "NUMBER"
  • parseFloat fallback in the update path (line 641) handles string-coerced numbers from YAML gracefully

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 34.5 AIC · ⌖ 5.02 AIC · ⊞ 7K
Comment /matt to run again

expect(inferFieldDataType("score", Infinity, datePattern)).toBe("SINGLE_SELECT");
});

it("returns SINGLE_SELECT for boolean field value", () => {

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.

[/tdd] Missing test: NaN is not covered by inferFieldDataType unit tests — only Infinity is tested as a non-finite case.

💡 Suggested test
it('returns SINGLE_SELECT for NaN', () => {
  expect(inferFieldDataType('score', NaN, datePattern)).toBe('SINGLE_SELECT');
});

NaN satisfies typeof value === 'number' but fails Number.isFinite, so it correctly falls to SINGLE_SELECT. A test confirms this and prevents future regressions if the guard condition changes.

@copilot please address this.

Comment thread actions/setup/js/update_project.cjs Outdated
core.warning(`Failed to create field "${fieldName}": ${getErrorMessage(createError)}`);
continue;
}
} else if (isNumberField) {

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.

[/diagnosing-bugs] The new NUMBER field creation GraphQL fragment only requests id, name, and dataType — but the TEXT field creation branch (line ~557) also requests the options fragment via ProjectV2SingleSelectField. The NUMBER branch doesn't need options, but the inconsistency in the inline fragment pattern is worth noting: if the API response ever returns a union type, the missing fragment could silently return null for field.

💡 Suggestion

This is low-risk since NUMBER maps to ProjectV2Field (not ProjectV2SingleSelectField), but consider adding a comment explaining why only the ProjectV2Field fragment is needed here — matching the defensive inline-comment style used elsewhere in this function.

@copilot please address this.

@github-actions

Copy link
Copy Markdown
Contributor

Warning

threat detection engine error
The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding.

Details

The threat detection engine failed to produce results.

Review the workflow run logs for details.

🧪 Test Quality Sentinel Report

⚠️ Test Quality Score: 68/100 — Acceptable

Analyzed 29 test(s): 27 design, 2 implementation, 0 violations.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 73 AIC · ⊞ 8.4K ·
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

Triage Summary

  • Category: bug
  • Risk: low
  • Priority Score: 59/100 (impact 28 + urgency 15 + quality 16)
  • Recommended Action: fast_track

Fixes NUMBER field type inference bug in update_project.cjs (spurious warnings / wrong field type creation). Has tests, not draft.

Generated by 🔧 PR Triage Agent · auto · 54.9 AIC · ⌖ 5.64 AIC · ⊞ 7.9K ·

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

… branch

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Fixed in commit fix: check isNumberField before isDateField to fix unreachable NUMBER branch.

The isNumberField check now comes before the name-based isDateField check in applyFieldUpdates. Fields whose names contain "date" but whose values are finite numbers now correctly create/use a NUMBER field. The existing invalid-date warning is preserved for non-numeric, non-date-formatted values. Added a inferFieldDataType unit test and an integration test covering this case.

@pelikhan
pelikhan merged commit 071cae7 into main Jul 30, 2026
8 checks passed
@pelikhan
pelikhan deleted the copilot/update-project-numeric-fields-inference branch July 30, 2026 09:50
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

Warning

threat detection engine error
The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding.

Details

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@copilot please run the skill, address unresolved review feedback if any, and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 9.62 AIC · ⊞ 8.7K ·
Comment /souschef to run again

@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.84.1

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.

update_project: numeric fields are inferred as SINGLE_SELECT and skipped

4 participants