Skip to content

fix(ai): honor the documented GJC_NO_STRICT bypass - #3305

Merged
Yeachan-Heo merged 1 commit into
Yeachan-Heo:devfrom
10kH:fix/no-strict-drift
Jul 29, 2026
Merged

fix(ai): honor the documented GJC_NO_STRICT bypass#3305
Yeachan-Heo merged 1 commit into
Yeachan-Heo:devfrom
10kH:fix/no-strict-drift

Conversation

@10kH

@10kH 10kH commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Another documented-but-unread name, found by checking the canonical env reference against what other docs teach.

Problem

docs/ai-schema-normalize.md:32
  adaptSchemaForStrict ... consults `GJC_NO_STRICT` (env `GJC_NO_STRICT`) for the global bypass.

packages/ai/src/utils/schema/adapt.ts:14
  export const NO_STRICT = $flag("PI_NO_STRICT");   // documented name never read

Same PI_GJC_ drift class as #2827 / #2943 / #3041 / #3171 / #3245 / #3296, and like #3296 the drift costs something concrete: this flag is the escape hatch that turns off OpenAI-style strict function-schema enforcement. An operator working around a provider that rejects strict schemas sets the documented name, and strict mode stays on.

Fix

$pickflag("GJC_NO_STRICT", "PI_NO_STRICT"). $pickflag applies the same boolean contract $flag already used — first non-empty key decides, case-insensitive 1/true/yes/on — so legacy behavior is unchanged and the canonical name simply takes precedence.

The boolean contract is right here, unlike #3296: this is a bypass, so GJC_NO_STRICT=0 meaning “stay strict” is the safe direction. In #3296 the same shape would have let =0 silently re-enable reading a token out of another application, which is why that one stayed presence-based. Calling that out because the two look superficially identical.

Also: a reference-page gap

GJC_NO_STRICT was taught only in the schema-normalisation note. docs/environment-variables.md opens by saying it is “derived from current code paths” and “documents only active behavior”, so a knob read in packages/ai/src/** belongs there. Added.

Tests

no-strict-env.test.ts runs each scenario in its own process, because NO_STRICT is a module-level constant: strict on by default, each name honoured, the documented boolean spellings accepted case-insensitively, an explicit falsey value respected, and the canonical name winning over a truthy legacy value.

Proof-first: reverting to the legacy-only read fails three of the six.

Verification

bun run check in packages/ai (whole-package biome + tsc): exit 0. New suite: 6 pass / 0 fail. Strict-named suites: 277 pass / 0 fail. Docs index regenerated; check:public-sync in sync.

@Yeachan-Heo Yeachan-Heo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Verdict: APPROVE — exact head 7709d367764b8b21a4a793ed822b911ee0a52065

Same PI_GJC_ documented-but-unread drift class as #2827/#2943/#3041/#3171/#3245/#3296, gating strict-schema enforcement bypass. Documented GJC_NO_STRICT alias verified as a genuine, correctly-behaving boolean.

Checks performed:

  • Pre-fix defect confirmed: docs/ai-schema-normalize.md:32 documents GJC_NO_STRICT; pre-fix adapt.ts:14 read only $flag("PI_NO_STRICT") — the documented name was a silent no-op, matching the PR's claim.
  • $pickflag semantics verified directly (packages/utils/src/env.ts:284-290): iterates keys in order, returns the boolean value of the first key with a non-empty value (not first-truthy) — i.e., an explicit GJC_NO_STRICT=0 correctly wins over a set PI_NO_STRICT=1 and resolves to false, matching the PR's "canonical name wins over a truthy legacy value" test case exactly.
  • Boolean-vs-presence contract choice justified: unlike #3296 (GJC_AUTH_NO_BORROW, presence-based because =0 re-enabling token borrow would be the unsafe direction), here GJC_NO_STRICT=0 meaning "stay strict" is the safe failure direction, so routing through the existing $pickflag boolean contract (rather than a bespoke presence check) is the correct choice — the PR explicitly calls out and reasons through this distinction rather than copy-pasting the #3296 pattern blind.
  • Docs reference-page gap: GJC_NO_STRICT added to docs/environment-variables.md's OpenAI-code table, consistent with that file's stated scope ("derived from current code paths… documents only active behavior").
  • Tests: hermetic — each scenario spawns a fresh process via no-strict-probe.ts since NO_STRICT is a module-level constant, correctly avoiding a stale-import false pass. Six cases: default-strict, documented-name honored, legacy-name honored, case-insensitive boolean spellings, explicit falsey documented value, and canonical-wins-over-truthy-legacy. Proof-first claim (reverting to legacy-only fails 3/6) is consistent with the diff.
  • CI: all applicable checks pass on the exact head, including the new test:packages/ai/test/no-strict-env.test.ts job explicitly green.
  • Novelty: no other open PR touches adapt.ts's NO_STRICT resolution; not a duplicate.
  • No automated reviewer comments present.

No merge action taken — read-only review verdict only.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@10kH
10kH force-pushed the fix/no-strict-drift branch from 7709d36 to d0efab7 Compare July 27, 2026 13:43

@Yeachan-Heo Yeachan-Heo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Verdict: APPROVE — exact head d0efab7e95bdd58e254423a21ff8b8bf97ce780e

Rebase-only refresh of the prior exact-head review at 7709d367764b8b21a4a793ed822b911ee0a52065 (APPROVE).

Checks performed:

  • Content identity confirmed, not assumed: diff <(git show 7709d367 --format= -- docs/environment-variables.md packages/ai/src/utils/schema/adapt.ts packages/ai/test/fixtures/no-strict-probe.ts packages/ai/test/no-strict-env.test.ts) <(git show d0efab7e --format= -- docs/environment-variables.md packages/ai/src/utils/schema/adapt.ts packages/ai/test/fixtures/no-strict-probe.ts packages/ai/test/no-strict-env.test.ts) is empty — the PR's own commit is byte-for-byte identical to the version the prior review validated. CHANGELOG.md is intentionally excluded from this file set: its diff context shifted because independently-merged dev commits inserted new entries above the same insertion point, which is expected rebase churn, not a content change to this PR's own line.
  • Rebase mechanics verified: git merge-base confirms this PR carries the same single commit both before and after the rebase; every additional commit between the two heads is an independently-merged dev commit (own-PR-numbered), not new work folded into this PR.
  • Exact-head terminal CI: 17 success / 0 failure / 0 pending / 5 skipped (total 22). No pending/queued checks remain.

Prior technical analysis still applies verbatim to this head.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@10kH
10kH force-pushed the fix/no-strict-drift branch from d0efab7 to 8244392 Compare July 27, 2026 23:01

@Yeachan-Heo Yeachan-Heo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

MERGE_READY (verdict reconciliation — exact head)

Reattaching the existing durable verdict to the current exact head 824439238ddd2211f023b2c24ffc7bc1d8503216 (base dev @ fbb5670709a1b1e04abddd1cc4827143fb63b876). This is a reconciliation, not a new review: the prior APPROVED was submitted at d0efab7e, and the head moved by rebase only.

Evidence:

  • Normalized patch of d0efab7e and 82443923 (file list + hunk bodies, hunk headers excluded) is byte-identical — SHA256 5a95ab30… for both. File-level shape is unchanged: docs/environment-variables.md +1-0, packages/ai/CHANGELOG.md +1-0, packages/ai/src/utils/schema/adapt.ts +2-2, packages/ai/test/fixtures/no-strict-probe.ts +5-0, packages/ai/test/no-strict-env.test.ts +59-0, packages/coding-agent/src/internal-urls/docs-index.generated.ts +1-1.
  • Only the parent changed (b853f15dfbb56707). No source, test, or docs delta.
  • Exact-head checks: 17 success, 6 skipped, 0 failure. mergeable_state: clean.

Verdict carries forward unchanged. Merge remains gated on dev returning green (current dev @ fbb56707 is red).


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/no-strict-drift branch from 8244392 to 9925a94 Compare July 28, 2026 03:04
docs/ai-schema-normalize.md:32 says adaptSchemaForStrict "consults
GJC_NO_STRICT (env GJC_NO_STRICT) for the global bypass". adapt.ts:14 read
$flag("PI_NO_STRICT"), so the documented name was a silent no-op.

Same PI_ -> GJC_ drift class as Yeachan-Heo#2827 / Yeachan-Heo#2943 / Yeachan-Heo#3041 / Yeachan-Heo#3171 / Yeachan-Heo#3245 / Yeachan-Heo#3296.
The consequence here is a stuck escape hatch: this flag is what turns off
OpenAI-style strict function-schema enforcement, so an operator working around a
provider that rejects strict schemas set the documented name and strict mode
stayed on.

Resolved with $pickflag("GJC_NO_STRICT", "PI_NO_STRICT"). $pickflag applies
the same boolean contract $flag already used — first non-empty key decides,
case-insensitive 1/true/yes/on — so the legacy behavior is unchanged and the
canonical name simply takes precedence. This is a bypass rather than a privacy
opt-out, so the boolean contract is the right shape here, unlike Yeachan-Heo#3296 where an
explicit 0 must not re-enable borrowing.

Also lists GJC_NO_STRICT in docs/environment-variables.md. That page states it
is derived from the current code paths and documents only active behavior, but
this knob was taught only in the schema-normalisation note.

Regression: six cases covering default-on strict mode, each name honoured, the
documented boolean spellings, an explicit falsey value, and the canonical name
winning over a truthy legacy value. Reverting to the legacy-only read fails
three of them.
@Yeachan-Heo
Yeachan-Heo force-pushed the fix/no-strict-drift branch from 9925a94 to 49be461 Compare July 29, 2026 00:53

@Yeachan-Heo Yeachan-Heo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Verdict: APPROVE — exact head 49be461ef0ba39486fded9987d206dcfa297db56.

Behavior and release-surface revalidation:

  • NO_STRICT now resolves with $pickflag("GJC_NO_STRICT", "PI_NO_STRICT"), so the documented canonical name works, the legacy alias remains supported, and the first non-empty canonical value wins even when explicitly falsey. That safe-direction boolean contract is appropriate for a bypass flag.
  • Six fresh-process scenarios cover default strict mode, both names, case-insensitive truthy spellings, explicit false, and canonical-over-legacy precedence.
  • The semantic rebase lands on current dev parent f3a34362243e9ddde049844094e52547557328f9. The changelog entry is under Unreleased; the environment reference was merged with current content and the internal docs index regenerated from source rather than conflict-resolved by hand.
  • Local focused suite: 6/6 passed. AI typecheck, Biome, generated-doc public-sync, and diff checks passed.
  • Exact-head CI is terminal with every reported check SUCCESS or SKIPPED, including the focused NO_STRICT test plus both AI and coding-agent checks.
  • Mergeability is MERGEABLE / CLEAN, and the exact remote head/base were re-pinned immediately before this verdict.

— GJC provider/trust review, 2026-07-28

@Yeachan-Heo
Yeachan-Heo merged commit 409dc98 into Yeachan-Heo:dev Jul 29, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants