Skip to content

test(sections): pin every parse-refusal message a user can see - #419

Merged
Vivswan merged 1 commit into
mainfrom
wt/refusal-messages
Sep 23, 2026
Merged

Vivswan merged 1 commit into
mainfrom
wt/refusal-messages

Conversation

@Vivswan

@Vivswan Vivswan commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

What this changes

Before After
Refusal-message literals a user can read at parse time 366 366
Pinned as the rendered key.path: message line, through validateSectionShapes 239 366
Pinned only by a regex or substring check, or not at all 127 0
A new refusal no test spells ships silently the census test fails, naming the source file and line

The census failure, as test/sections/refusal-messages.test.ts prints it:

src/sections/milestones/schema.ts:16: "probe"

A pinned line, as the run prints it:

environments[0].prevent_self_review: the "prod" entry declares prevent_self_review: true without reviewers; GitHub keeps the flag only on a required-reviewers rule, which needs at least one reviewer. Declare a reviewer, or write prevent_self_review: false

How

  • Census scope. Every string literal in a section schema slice, a shared schema helper, or compilable-form.ts is a refusal message unless its position is in the listed exclusions. In section modules, module.ts, repo-secrets.ts, and problem.ts, every literal inside a message-shaped object ({path, message}), an error:/consequence: property, or an issue-builder body is a message. No reach or helper analysis: a literal cannot hide from a file scan.
  • Reader. Message literals are read off the source AST with oxc-parser (already a dependency) walked by estree-walker (new devDependency), never by regex over source text.
Source How it is read Literals
src/sections/*/schema.ts (26 slices), shared/{schema-helpers,setup-schema,roles,renamed-key,raw-values}.ts, compilable-form.ts every string literal and template piece, minus the exclusions below 265
src/sections/*/index.ts (26 modules), environments/{nested,branch-policies,protection-rules}.ts, contract/module.ts, shared/repo-secrets.ts, problem.ts the message positions only (the full list is in Technical details) 101
  • Exclusion positions. A closed list; adding a message spelling needs no census change, adding a data spelling needs one line in one of these lists.
Position Example
property key { "error": ... }, the key itself
module specifier import { z } from "zod"
type position a literal type, an annotation
vocabulary call argument 0 of z.enum([...]), z.literal("web"), .default(...), .includes("<num>")
value method .split(","), .join(", "), .startsWith(...), new RegExp(...), new Set([...])
comparison or case label name === "", case "boolean":
data field path, code, id, route, kind, check, nameKey, example, and the arrays under one
as const vocabulary ["a", "b"] as const, reached through arrays, objects, and properties only
schema twin the argument of .meta({...}) or conditional(...)
regex source a String.raw template
invariant a BUG: message
DATA_CONSTANTS a named constant holding a key list, a vocabulary, or a pattern piece
DATA_FUNCTIONS a function that assembles regex source
DATA_ARGUMENTS a data argument of a local factory (bareRule("creation"))
  • Pieces and whole messages. A piece of a longer message (a + operand, a template hole, a conditional arm, a slice helper's return, a registered piece argument such as closedKeyError("security_and_analysis", ...)) pins by containment. Prose (16 characters or more with a space) pins by containment; anything shorter or spaceless pins only as the whole message of a rendered line, after : and up to the end of the string or line.
  • Pins. New test/sections/<key>/schema.test.ts for actions, collaborators, custom_properties, deploy_keys, environments, milestones, pages, repository, workflows. The eight existing ones (branches, check_suite_preferences, interaction_limits, labels, rulesets, secret_scanning_custom_patterns, teams, webhooks) now spell the exact line where a custom message is at stake; zod's own default wording stays matched loosely.
  • Shared wordings pinned once. test/sections/list-wrapper-schema.test.ts (wrapper directives, the renamed policy key, the list-or-wrapper and plain-mapping lines), roles.test.ts (permissions), secret-variable-schema.test.ts (secret entry keys), test/problem.test.ts (the four document-level issue builders).

Proof

  • Pinned messages: 366 of 366 literals, each in the section's test/sections/<key>/ tests or the shared test that owns the wording.
  • Gates: env -u NODE_OPTIONS bun run typecheck, bun run knip, bun run lint green.
  • Tests: bun test test/sections test/problem.test.ts --timeout 120000: 1557 pass.
  • E2e: bun run test:e2e --sections labels,webhooks,milestones,workflows: 89/89; --sections secret_scanning_custom_patterns,milestones: 21/21; --sections milestones,workflows: 16/16.
  • Two new refusal scenarios for the sections that had none: milestones-invalid-state-rejected.yml and workflows-invalid-state-rejected.yml (a state: paused entry exits 1 before any request, naming the entry and the accepted values).
  • Red census: every planted spelling in a real source fails naming the file, the line, and the literal, and the census is green after the revert (the spellings are listed in Technical details). A listed source file removed fails naming its path.
Technical details

Reviewer notes

  • When the census fails: it prints path:line: "fragment". Either spell the message in the section's test/sections/<key>/schema.test.ts (the rendered key.path: message line, through validateSectionShapes) or, for a shared helper's wording, in the shared test that owns it.
  • Layout: the tests follow the test/sections/<key>/ layout from refactor(test): fold the section test mirror into test/sections #402; the PR is based on main.
  • Why an AST walk: z.toJSONSchema does not export messages, and neither zod nor zod-to-json-schema offers a message extractor, so the census is the AST walk.
  • Why estree-walker (3.0.3, no runtime dependencies; its one dependency is @types/estree): it walks any subtree, skips on demand, starts at any node, and hands each step its parent and key, which the reference and scope tracking need. oxc's own Visitor has neither skip nor a sub-tree start.
  • Not in this census: the engine's own document lines in src/engine/validate.ts (null state, truncation, cycle, closed surface), src/engine/secret-refs.ts, and src/plain-data.ts (nonPlainKind, rendered through the engine and pinned in test/engine/validate.test.ts). Two defensive defaults there (a value of the key's own type) are unreachable through the engine, so they cannot be pinned by an input; a note for the owner.
  • requirePlainMapping's line is pinned through the section shape directly: the engine's plainness walk refuses a tagged value first, so no document reaches it.
  • Four exact-output rows (feature status, dependabot_security_updates, a squash message without its title, an invalid squash pair) already lived in repository/repository.test.ts, so repository/schema.test.ts does not repeat them.
  • src/problem.ts and compilable-form.ts: in problem.ts the message positions are the ...Issue builders' bodies and the advice constants they name; in compilable-form.ts every literal outside render and codePointEscape (regex builders) and the data constants is a message, the reason column of MALFORMED_ESCAPES included. The RegExp engine's messages pass through unread.
  • params.legal is a message position: the engine frames the line (has no empty state; write ...) and the module supplies the legal text, so the census reads the module's literal and the engine test pins the framed line.
  • The regex check's own reasons are pinned in compilable-form.test.ts with independent literals, so the pattern refusal's inner text is a deliberate change too.
  • A pin over the 256-character line cap is split as "key[0].path: " + String(KEY) + "...": the String(...) operands keep the + chain a plain concatenation the census reads as one asserted string, where a template would hide the text in a hole.
  • Sections with no new file: those whose only refusals are shared or already pinned in <key>.test.ts (autolinks, the four secret and two variable families, code scanning and code quality setup).

Message positions in the modules

In src/sections/*/index.ts, environments/{nested,branch-policies,protection-rules}.ts, contract/module.ts, shared/repo-secrets.ts, and problem.ts, a message is:

  • the literals inside a message:/error:/consequence: value;
  • the top-level or function-local constant and the top-level function such a value names (one hop);
  • the legal: value of an issue's params;
  • an ...Issue builder's body;
  • a list section's top-level noun:, and the noun argument of a registered duplicate-issue helper (identifiedBy(..., "workflow"), duplicateVariableNameIssues(entries, "...")).

A Live* shape's transform (a GET body outside the documented API) is not a parse position.

Exclusions in full, one planted control literal each

  • a property key; an import or export specifier; a type position (a literal type, an annotation);
  • argument 0 of a vocabulary call: z.enum([...]), z.literal("web"), .default(...), .includes("<num>"), z.discriminatedUnion("type", ...); the message argument after it is a message. The value methods split, join, replace, startsWith, new RegExp(...), new Set([...]), and the receiver they are called on (the .join(" or ") conjunction in the squash-pair hint is pinned today through the pair table);
  • a comparison or a case label; a data field (path, code, id, route, kind, check, nameKey, example, ...) and the arrays under one; name is not one (ECHO_CARRIER.name is user text), and the nameKey/example tokens of the branches actor table are data the surrounding template pieces pin;
  • an as const vocabulary, reached through arrays, objects, and properties only (a call inside it, rule("creation", { error }), is read), and never a prose-length literal (the wrapper directives text in WRAPPER_KINDS is a message); a JSON Schema twin under .meta({...}) or conditional(...); a String.raw template (a regex source; any other tag is a message); a BUG: invariant;
  • a named constant in DATA_CONSTANTS (key lists, vocabularies, pattern pieces); a regex-building function in DATA_FUNCTIONS;
  • a data argument of a registered local factory (bareRule("creation"), actorList(holder, "users"), boundedString(max, "code points", ...), sectionFailure("live-shape", ...)).

Tripwire controls

  • one planted literal per exclusion position is silent (a .meta schema twin, a regex-building function, new RegExp(...), new Set([...]), and a String.raw source among them); the DATA_CONSTANTS names are checked against the constants the sources declare, so the list cannot go stale;
  • every planted message is a finding by construction, in every spelling: a hole-free template, a one-hole template with literal arms, a + chain, a type assertion, a let assigned later, a computed key, a local helper's argument, a helper whose message parameter is called, a helper three calls deep, a message read off a local table, a for loop over messages, a message-shaped object built by a module helper, a module function a message names, an issue builder's return and the shape helper it names, a tag other than String.raw, a message inside an as const table, the message argument of z.enum(values, message) and z.literal(value, message);
  • the same messages pinned as a sentence, a template with the same holes, or a + chain pass; a scenario pins through its expect lists only;
  • a listed source that is gone fails naming its path; a source that does not parse fails rather than reading as pinned.

Red census, each spelling planted in a real source then reverted

  • error: <string>"Color required" (a type assertion): "Color required";
  • function called(message: () => string) { return z.string({ error: message() }) } with called(() => "probe2"): "probe2";
  • function plantedIssues() { return [{ path: "[0].state", message: "probe3" }] } in workflows/index.ts: "probe3";
  • function chainA() { return chainB() } function chainB() { return "probe4" }: "probe4";
  • function titled(message: string) { return z.string().min(1, message) } with titled("probe5"): "probe5";
  • for (const m of ["probe6"]) { ctx.addIssue({ message: m }) }: "probe6", no crash;
  • error: \probe7`(a hole-free template):"probe7"`;
  • const reasons = { bad: "probe8" }; error: reasons.bad: "probe8";
  • { ["error"]: "probe9" }: "probe9"; let msg: string; msg = "probe10"; error: msg: "probe10";
  • error: "Please " + "enter text": "enter text" (the "Please " piece is contained in another pin);
  • a new .refine(..., "<sentence>") in labels/schema.ts and a new reason row in compilable-form.ts: each named by file and line;
  • z.custom(...).transform((value, ctx) => { ctx.addIssue({ message: "probe11" }) }) in contract/module.ts (a routed shape, not a Live* one): "probe11";
  • identifiedBy("workflows", "path", "planted workflow noun") in workflows/index.ts and a planted noun in environments/nested.ts: each named by file and line;
  • plantedTag\probe tagged`, [rule("creation", { error: "..." })] as const, z.enum(values, "Please pick a planted state"), z.literal(v, "probe lit"), message: plantedWhy()in a module, anddescribePlantedShape()` named by an issue builder: each named by file and line;
  • a planted directives sentence in WRAPPER_KINDS (as const), a planted beside arm in routedListShape (a function-local constant), a planted params.legal value, and "a plist" in describeValue: each named by file and line;
  • a listed source file removed: refusalSources fails naming its path.

Known limits

Each an over-count (a pin found where a reader might not expect one; none lets a message through):

  • a pin is a sentence anywhere in a test's asserted strings, so a sentence in a test.each row label counts as one;
  • a sentence pinned under the shape's own path (0.protection...) counts for the engine's branches[0].protection... line too;
  • a custom message spelled exactly like a zod default whole line (Invalid input) reads as pinned by that line;
  • a whole terse message is matched after any : in an asserted line, not only the one that follows its key path;
  • a short piece (under 16 characters) pins at word boundaries, so a list inside comma list no longer pins it; a longer piece pins by containment;
  • a string that is an input to a test (not an expectation) pins like any other string of the test;
  • a negative scenario list (stdout_lacks, never) counts as a pin like any expect list;
  • a string-literal type in a test (type Verdict = "probe") counts as a pin;
  • a template with holes pins by its space-joined quasis, so a message across two quasis pins even when the hole's text differs;
  • a module-local const message = "..." that no message: property names is not read;
  • the pin corpus is every .ts and .yml under test/, harness files included (the e2e runner, mocks, generators), so a short piece can be pinned by one of their strings.

Not read

By the owner's ruling (parse refusals only): plan text, outcome strings, and notes in the section modules, module.ts, repo-secrets.ts, and the describeProblem lines of problem.ts outside the issue builders; the RegExp engine's own error text, which compileFailure passes through; regex sources spelled as String.raw templates.

Recorded, not built

Text on the receiver of a .join() as a message; a message table keyed text:.

Wording review

Every message was read against the criteria "names the key, gives the fix, agrees with the docs". The key path is on every rendered line, every message names a fix or the accepted forms, and the caps and ranges (wait timer 43200, 6 reviewers, 10 pinned, 100-character descriptions, 100 bypass users, 1 to 1000, 20 topics, 0 to 6 reviews, the deploy-key algorithms) agree with docs/sections/*.docs.yml.

Wording fix Count
Messages reworded 0

Line accounting

+2368 / -96 across 27 files; every added line is under test/ except the estree-walker devDependency in package.json and bun.lock.

BEGIN_COMMIT_OVERRIDE
test(sections): pin every parse-refusal message a user can see

Every custom refusal literal in the section schema slices, the shared schema helpers, the file-only validate hooks, and the document-level issue builders is now spelled by a test through validateSectionShapes, the entry point the action uses.
A census test reads every string literal of the schema slices and shared helpers off the source AST with oxc-parser and estree-walker, minus a closed list of data positions.
It fails naming the file, the line, and the literal of any message no test string pins, so a new refusal cannot ship unpinned.
Before, 239 of the 366 message literals had a sentence-level pin; now all 366 do, each in the section's test/sections// tests or the shared test that owns the wording.
END_COMMIT_OVERRIDE

Copilot AI balanced review requested due to automatic review settings September 22, 2026 10:47
@Vivswan Vivswan added the merge-when-green Owner approved: merge once every gate is green label Sep 22, 2026
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

File size check

0 over a hard cap (fails), 33 warning(s).

File Size Tier Cap
.github/scripts/gen-inputs-table.ts:54 11 comment lines warn 10
.github/scripts/generated.ts:28 200 chars warn 150
.github/scripts/release-pipeline.ts:6 156 chars warn 150
.github/scripts/release-pipeline.ts:453 151 chars warn 150
.github/scripts/release-pipeline.ts:1247 153 chars warn 150
.github/scripts/release-pipeline.ts:1 34 comment lines (header) warn 25
.github/scripts/release-pipeline.ts:449 14 comment lines warn 10
.github/workflows/post-green.yml:29 153 chars warn 150
.github/workflows/update-release-pr.yml:109 14 comment lines warn 10
docs/upgrading/v2-to-v3.md 1276 lines warn 1040
src/engine/layers.ts:217 157 chars warn 150
src/flows/settings-write.ts:142 159 chars warn 150
src/flows/settings-write.ts:30 11 comment lines warn 10
src/flows/snapshot.ts:189 13 comment lines warn 10
src/github/secret-scan.ts:43 11 comment lines warn 10
src/schema.ts:186 153 chars warn 150
src/schema.ts:197 176 chars warn 150
src/sections/contract/errors.ts:14 14 comment lines warn 10
src/sections/contract/module.ts:963 185 chars warn 150
src/sections/contract/module.ts:627 12 comment lines warn 10
src/sections/contract/module.ts:897 12 comment lines warn 10
src/sections/secret_scanning_custom_patterns/compilable-form.ts:382 161 chars warn 150
src/sections/shared/roles.ts:43 13 comment lines warn 10
src/types.ts:16 156 chars warn 150
test/docs/guides.test.ts:451 155 chars warn 150
test/e2e/generators.ts 2633 lines warn 2560
test/e2e/generators.ts:1703 166 chars warn 150
test/e2e/generators.ts:1857 161 chars warn 150
test/e2e/generators.ts:1666 12 comment lines warn 10
test/engine/execute.test.ts:617 152 chars warn 150
test/flows/merge-parity.test.ts:63 164 chars warn 150
test/scripts/auto-fix-allowlist.test.ts:12 12 comment lines warn 10
test/sections/refusal-messages.test.ts:61 19 comment lines warn 10

Split the file, wrap the line, shorten or exempt the comment, or list the path in .file-size-allow.local with a # reason.

5 managed file(s) skipped; repo-platform owns them.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census can accept unasserted strings as pins and omits user-visible messages produced by imported helpers.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
What changed in this PR

Adds exact coverage for user-visible parse-refusal messages and an AST-based census to detect unpinned messages.

Changes:

  • Adds section and shared-schema refusal tests.
  • Adds invalid-state e2e scenarios for milestones and workflows.
  • Adds an AST census for refusal-message coverage.
File Description
test/​sections/​actions/​schema.test.ts Pins actions refusal messages.
test/​sections/​branches/​schema.test.ts Replaces partial message matches with exact wording.
test/​sections/​check_suite_preferences/​schema.test.ts Pins app ID errors.
test/​sections/​collaborators/​schema.test.ts Covers unsupported collaborator keys.
test/​sections/​custom_properties/​schema.test.ts Covers ambiguous and invalid property values.
test/​sections/​deploy_keys/​schema.test.ts Pins deploy-key validation messages.
test/​sections/​environments/​schema.test.ts Pins environment validation messages.
test/​sections/​interaction_limits/​schema.test.ts Replaces regex checks with exact messages.
test/​sections/​labels/​schema.test.ts Pins color and description errors.
test/​sections/​list-wrapper-schema.test.ts Covers shared wrapper and mapping errors.
test/​sections/​milestones/​scenarios/​milestones-invalid-state-rejected.yml Adds invalid milestone state coverage.
test/​sections/​milestones/​schema.test.ts Pins due-date errors.
test/​sections/​pages/​schema.test.ts Covers read-only Pages fields.
test/​sections/​refusal-messages.test.ts Adds the AST-based message census.
test/​sections/​repository/​schema.test.ts Pins repository-setting refusals.
test/​sections/​roles.test.ts Pins shared permission errors.
test/​sections/​rulesets/​schema.test.ts Expands exact ruleset-message assertions.
test/​sections/​secret_scanning_custom_patterns/​schema.test.ts Pins pattern validation output.
test/​sections/​secret-variable-schema.test.ts Covers unsupported secret-entry keys.
test/​sections/​teams/​schema.test.ts Pins team slug and permission errors.
test/​sections/​webhooks/​schema.test.ts Covers misplaced webhook secrets.
test/​sections/​workflows/​scenarios/​workflows-invalid-state-rejected.yml Adds invalid workflow state coverage.
test/​sections/​workflows/​schema.test.ts Covers unsupported workflow keys.
test/​problem.test.ts Pins document-level issue builders.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/sections/refusal-messages.test.ts Outdated
Comment thread test/sections/refusal-messages.test.ts Outdated
Copilot AI review requested due to automatic review settings September 22, 2026 11:27
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from 264724a to 21a2709 Compare September 22, 2026 11:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census can accept unasserted literals as pins and omit messages returned by named functions.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)

Comment thread test/sections/refusal-messages.test.ts Outdated
Copilot AI review requested due to automatic review settings September 22, 2026 12:02
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from 21a2709 to 9f2ff05 Compare September 22, 2026 12:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census can falsely accept long single-token messages when they appear only as unrelated substrings.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (3)

Comment thread test/sections/refusal-messages.test.ts Outdated
Copilot AI review requested due to automatic review settings September 22, 2026 12:15
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from 9f2ff05 to e3eb4a7 Compare September 22, 2026 12:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Short template-based refusal messages can still bypass the new census without a pin.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (1)

Comment thread test/sections/refusal-messages.test.ts Outdated
Copilot AI review requested due to automatic review settings September 22, 2026 12:38
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from e3eb4a7 to 38da58e Compare September 22, 2026 12:38
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from 38da58e to eed7b98 Compare September 22, 2026 12:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census omits parse-refusal messages generated by validateSectionShapes itself, leaving its claimed coverage incomplete.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (1)

Comment thread test/sections/refusal-messages.test.ts Outdated
Copilot AI review requested due to automatic review settings September 22, 2026 12:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Reachable parse-refusal messages from the validation engine remain outside the census despite the PR's completeness claim.

Review effort: Balanced
Findings: None

Resolved since last review (1)

Copilot AI review requested due to automatic review settings September 22, 2026 13:16
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from eed7b98 to fc2ecaf Compare September 22, 2026 13:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census can miss table-backed messages and exported arrow-function helpers.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)

Comment thread test/sections/refusal-messages.test.ts Outdated
Comment thread test/sections/refusal-messages.test.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census skips a real parse-refusal message emitted inside the routed list-shape transform.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (2)

Comment thread test/sections/refusal-messages.test.ts Outdated
Copilot AI review requested due to automatic review settings September 22, 2026 14:49
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from 6510df0 to 261d37f Compare September 22, 2026 14:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census misses user-visible wording produced by local helpers called from issue builders.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (1)

Comment thread test/sections/refusal-messages.test.ts
Copilot AI review requested due to automatic review settings September 22, 2026 15:20
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from 261d37f to 8e76e77 Compare September 22, 2026 15:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census omits current validate-helper message arguments and refusal-producing source files, leaving gaps in its coverage guarantee.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
Resolved since last review (1)

Comment thread test/sections/refusal-messages.test.ts Outdated
Comment thread test/sections/refusal-messages.test.ts
Copilot AI review requested due to automatic review settings September 22, 2026 15:29
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from 8e76e77 to ee633c9 Compare September 22, 2026 15:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The census omits the shared repository-variable validator and therefore misses user-visible duplicate-variable wording.

Review effort: Balanced
Findings: None

Resolved since last review (2)

Copilot AI review requested due to automatic review settings September 22, 2026 15:54
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from ee633c9 to 3ba90d6 Compare September 22, 2026 15:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The census excludes two user-visible refusal literals that it is intended to guard.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)

Comment thread test/sections/refusal-messages.test.ts Outdated
Comment thread test/sections/refusal-messages.test.ts Outdated
Copilot AI review requested due to automatic review settings September 22, 2026 15:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The census can omit messages stored in registered constants or terse as const message objects.

Review effort: Balanced
Findings: None

Resolved since last review (2)

Every custom refusal literal in the section schema slices, the shared schema helpers, the file-only validate hooks, and the document-level issue builders is now spelled by a test through validateSectionShapes, the entry point the action uses.
A census test reads every string literal of the schema slices and shared helpers off the source AST with oxc-parser and estree-walker, minus a closed list of data positions.
It fails naming the file, the line, and the literal of any message no test string pins, so a new refusal cannot ship unpinned.
Before, 239 of the 366 message literals had a sentence-level pin; now all 366 do, each in the section's test/sections/<key>/ tests or the shared test that owns the wording.
Copilot AI review requested due to automatic review settings September 23, 2026 01:14
@Vivswan
Vivswan force-pushed the wt/refusal-messages branch from 3ba90d6 to 16d301c Compare September 23, 2026 01:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The census omits the repository-variable source that supplies a user-visible duplicate-entry message.

Review effort: Balanced
Findings: None

@Vivswan
Vivswan merged commit 86ea647 into main Sep 23, 2026
33 checks passed
@Vivswan
Vivswan deleted the wt/refusal-messages branch September 23, 2026 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-when-green Owner approved: merge once every gate is green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants