Skip to content

[throwaway] CI gate probe: lint and type-check must fail (do not merge) - #701

Closed
StephanWald wants to merge 228 commits into
mainfrom
throwaway/ci-gate-probe
Closed

StephanWald wants to merge 228 commits into
mainfrom
throwaway/ci-gate-probe

Conversation

@StephanWald

Copy link
Copy Markdown
Member

Throwaway draft PR to confirm the new BBj CI gates fail on a real error. It will be closed and the branch deleted, never merged.

Its last two commits add the probes:

  • test/utils.test.ts: an unused constant, so Lint should fail.
  • test/logger.test.ts: a string assigned to a number constant, so Type-check test tree should fail.

Expected result: both gate steps run and fail, and Test still runs.

The branch is based on the unpushed v4.7 work, so the diff also includes that milestone's commits. Ignore them here.

🤖 Generated with Claude Code

stephan-wald and others added 30 commits September 26, 2026 10:18
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…admap

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…J interop key todo

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- interop-config.ts: DEFAULT_INTEROP_HOST/PORT, validateInteropConfig,
  formatInteropRejection (plain module, no imports)
- java-interop.ts: setConnectionConfig(host: unknown, port: unknown)
  validates through the shared module, adds getConnectionConfig()
- bbj-ws-manager.ts onInitialize passes raw initialization-option
  values straight through, no local default
- test/interop-config.test.ts: validator table plus end-to-end
  initialization-options coverage through LanguageServer.initialize

Addresses issues #509, #510, #581.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…hared validator

- main.ts onDidChangeConfiguration passes config.interop?.host and
  config.interop?.port straight into setConnectionConfig, no local
  default
- test/interop-config.test.ts: configuration-change coverage per
  field and both together, plus a source-text pin on the main.ts
  call site
- Confirms REF-02: interop-config.ts is now the only place under
  bbj-vscode/src/language declaring the default host or port

Addresses issues #509, #510, #581.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…d FIFOs

- isTokenizedFile now lstats before opening and refuses anything but a
  regular file, so a symlink, directory, FIFO, socket or device is never
  passed to open (a FIFO would block indefinitely)
- open requests O_NOFOLLOW and O_NONBLOCK where the platform defines them,
  and the opened handle is re-checked with fstat().isFile() to close the
  swap window between lstat and open
- adds symlink, directory, FIFO, open-flags and fstat-recheck test cases

Closes issue #585 (decompile probe hardening).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nd FIFOs

- statSize is exported and now uses lstat, returning undefined for anything
  but a regular file (symlink, directory, FIFO, socket, device), same as
  isTokenizedFile
- waitForDecompileOutput never takes a symlinked <input>.lst as output and
  times out instead
- Commands.cjs and the polling contract are unchanged

Closes issue #585 (decompile probe hardening).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A new machine-scoped bbj.formatter.javaPath setting chooses the java binary
the formatter spawns. formatter-java-resolver.ts checks a configured value
(absolute, exists, regular file, executable) and refuses with an error
naming the path and the problem instead of falling back to PATH; an empty
value is resolved by the module's own PATH walk, verified the same way.
The formatter's cp.spawn now always receives that verified absolute path.

Closes #605

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ehavior

Adds win32 PATHEXT-order, default-extensions, quoted-entry and
first-hit-wins cases, plus real-filesystem PATH-walk cases (a symlinked
executable accepted, a later PATH entry found, a directory named java
refused). All pass against the existing resolver with no production code
change: the Windows PATH-walk handling was already implemented as part of
the same module in the prior commit rather than split across two passes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…r guard's trust comment

Adds a Formatter Settings entry for the new setting to configuration.md.
Updates no-shell-command-construction.test.ts's stale comment (it said
document-formatter.ts ran java from PATH unconditionally) and pins that
document-formatter.ts imports resolveFormatterJava, calls it before
cp.spawn(, and never spawns a string literal as the java executable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…allback behind Workspace Trust

An untrusted workspace's client hands the server and its own association fallback only the
user-level bbj.configPath (or null), through one new helper (effectiveConfigPath in
config-path-trust.ts); a trusted workspace is unchanged. initializationOptions no longer
carries a client-side interop host/port default -- the server's shared validator owns them.

Closes issue #511

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ll middleware

RED: createConfigPathTrustMiddleware and gatedBbjSettings do not exist yet. Covers the push
path (didChangeConfiguration never calling next for a section list), the pull path
(workspace/configuration substitution), and the activate()-level wiring, issue #511.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ed middleware

createConfigPathTrustMiddleware builds and sends the bbj section itself (never calling the
library's next() for a section list, which re-reads the raw workspace value), replacing
configPath with the trust-gated effective value; the same substitution applies to
workspace/configuration pull answers. extension.ts wires it into clientOptions.middleware.

Closes issue #511

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… re-push

RED: registerTrustGrantRepush does not exist yet. Covers subscribing to
onDidGrantWorkspaceTrust, sending the gated bbj settings once on a grant, routing a rejected
send to onError, and the activate()-level subscription wiring, issue #511.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…granted

registerTrustGrantRepush subscribes to onDidGrantWorkspaceTrust and sends the gated bbj
settings once through the same builder the push path uses, so the workspace configPath takes
effect without a reload; a rejected send is routed to the output channel instead of escaping
as an unhandled rejection. Wired into startLanguageClient's context.subscriptions.

Closes issue #511

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
stephan-wald and others added 27 commits September 27, 2026 19:19
commands-cjs-harness.ts's CommandsModule interface gains named function
members for every command commands-cjs-execution.test.ts calls (run,
runBUI, runDWC, compile, denumber, decompileReplace, decompileReadonly,
openConfigFile, openPropertiesFile, openEnterpriseManager), replacing the
`unknown`-typed index-signature fallback. ConfigPathCacheModule gains a
setResolvedConfigPath member matching the `{ path, exists }` shape every
test actually passes. fakeVscode's showErrorMessage/showWarningMessage/
showInformationMessage/executeCommand and fakeProcessRunner's runProcess/
runProcessCallback are typed with their real parameter lists, so
`.mock.calls` tuples are no longer zero-length.

commands-cjs-execution.test.ts gets type-only fixes with no assertion or
title changes: a fakeProcessError() helper builds an Error carrying the
`cmd` field Node's ExecException type requires, an assertDefined()
assertion function narrows the optional Argv/ExecFileOptions `env` maps
two web-run tests read, and the two `appendLine` output-channel fakes
declare their string parameter so `.mock.calls.find()`'s destructured
predicate type-checks.

Whole-suite verification: two runs both show hookTimeoutSuites=0 and
interop5008=open matching baseline; the second run's FAILED_TEST set is
byte-identical to the phase baseline, and the first run's two extra
failures (installed-extension-e2e.test.ts, parser-keyword-statements.test.ts)
are the same pre-existing, unrelated contention-timing flakiness already
diagnosed in 114-02/114-05/114-06 under the same sustained external host
CPU load, confirmed here by re-running parser-keyword-statements.test.ts
standalone (332/332 passed) and diffing both files against the phase base
(untouched by this plan).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…forced case

Per issue #447 (D-15): an ungated describe block, always run (including CI with
nothing on :5008), uses the scriptable fake interop peer to force a
getAllClassNames MethodNotFound answer. It asserts the client-side fallback
latches to exactly one attempt, and the curated-package candidate probe still
resolves java.util.HashMap via getClassInfo requests. A second test confirms a
seeded index answers with no probe at all. A mutation probe against the
MethodNotFound comparison inside ensureCompleteClassIndex (never restored to
git) turned the latch test red before the fix was reverted, proving the guard
has teeth.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…construction

Per issue #447 (D-15): the live capability test now branches on what
getAllClassNames actually answered on the wire (observed via a
WireRecordingInteropService that wraps the real connection's sendRequest),
instead of comparing the client's own cached flag against its own probe
result. A second live describe forces getAllClassNames to MethodNotFound
through the same wrapSocket seam while every other request still reaches
the real backend, proving the fallback latch and the curated-package probe
against the real classpath. The kept code-action test reads the diagnostic
message through Diagnostic.getMessageString (LSP 3.18's string|MarkupContent).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…type-clean

- Drop three unused ast.js import names from validation.test.ts (clears
  matching TS6133 errors) and read diagnostic messages through
  Diagnostic.getMessageString wherever a string comparison needs one
- Load properties-reader in em-properties-reader-guard.test.ts through a
  module-level createRequire(import.meta.url) loader bound to requireCjs,
  clearing the no-require-imports finding without changing either test's
  assertions

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ings

- Drop unused imports/args across bbj-cpl-fallback-dedup, javadoc,
  lazy-prefix-loading, linking, live-parse-interleaving, on-save-kept-errors,
  setopts-catalog and utils test files, underscore-prefixing the handful of
  override parameters that must stay in the signature
- Add the NormalizedTextDocuments<TextDocument> type argument at every call
  site, switch Node-builtin imports to namespace form, drop the non-existent
  langium CancellationToken import, add missing .js import suffixes, and read
  diagnostic messages through Diagnostic.getMessageString
- Give JavadocProviderUnderTest's test constructor a real lazyLoad parameter
  forwarded to the base class so the two failing/mixed-fs tests' `super(false)`
  calls type-check (both tests' own readDirectory failures short-circuit before
  lazyLoad is ever read, so this is behaviour-neutral)
- Round out the two lazy-prefix-loading in-memory FileSystemProvider fakes
  with existsSync/readBinary/readBinarySync, mirroring their existing
  sync/async pairing pattern
- npx eslint src test --max-warnings 0 and npm run lint both exit 0; two
  whole-suite runs match baseline/suite-before.txt's FAILED_TEST set exactly

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…viders

- NormalizedTextDocuments<TextDocument> given its type argument in
  fake-text-document-connection.ts, live-parse-scheduling.test.ts and
  on-save-trigger.test.ts
- scope-cost-regression.test.ts, use-path-containment.test.ts and
  extensionless-use-target.test.ts's fake FileSystemProvider classes gain
  existsSync/readBinary/readBinarySync, mirroring their existing sync/async
  pairing
- use-path-containment.test.ts: fileNotResolvedErrors reads messages through
  Diagnostic.getMessageString, the extra readDirectorySync argument is
  dropped, and the possibly-undefined bbjClass reference is narrowed with a
  throwing check
- extensionless-use-target.test.ts: relative imports get .js suffixes and
  its diagnostic message read goes through Diagnostic.getMessageString

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- bbj-parser-service.test.ts: fakeDocument returns a document whose
  textDocument is writable (WritableTextDocumentDocument), not cast to any
- composer-codelens.test.ts: pass only the argument provideCodeLens declares
- composer-cue-single-source.test.ts: drop the ES2018-only dot-all regex
  flag, unneeded since [^\]] already matches newlines
- config-reload-host.test.ts: createFakeTarget's Mock-typed fake target is
  no longer intersected with RestartTarget's own plain-function signatures,
  and its overrides parameter is typed against the Mock-shaped fake
- extension-activation.test.ts: onNotificationMock is typed with the
  parameters the code calls it with
- extension-config-trust.test.ts: the fake WorkspaceConfiguration's get
  takes an optional default, matching vscode's own signature
- functional/installed-extension-e2e.test.ts: import from
  vscode-jsonrpc/node.js under Node16 module resolution
- java-interop-peer-guard.test.ts: mocked javadoc fixtures are typed as
  ClassDoc, the type that actually has fields/methods
- line-break-walk-termination.test.ts: diagnostic messages read through
  Diagnostic.getMessageString
- logger.test.ts: debugEnabled uses Boolean(false) so the comparison isn't
  narrowed to a same-value literal comparison

Two whole-suite runs after both tasks: FAILED_TEST lines byte-identical to
baseline/suite-before.txt (the 11-test linking.test.ts interop baseline),
hookTimeoutSuites=0, interop5008=open in both runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- line-break-validation.test.ts, line-break-single-line-if.test.ts,
  parser-keyword-statements.test.ts, unresolvable-type.test.ts each retype
  their local diagnostic-message helper to accept the real LSP
  Diagnostic[] list and read messages through Diagnostic.getMessageString
- fixes the remaining direct .message reads the same way (string |
  MarkupContent since LSP 3.18)
- no behaviour change: helper filtering/matching logic is unchanged text

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…e reads

- replace every string use of a diagnostic message with
  Diagnostic.getMessageString(d) in both files (string | MarkupContent
  since LSP 3.18), importing Diagnostic from vscode-languageserver
- add .js suffixes to classes.test.ts's relative imports (Node16
  resolution)
- variable-scoping.test.ts: drop the always-true `ref !== fieldDecl`
  clause from a find predicate (a SymbolRef can never be a FieldDecl,
  so the comparison was provably vacuous); the predicate selects the
  identical single reference as before
- whole suite matches the phase baseline exactly across two runs
  (FAILED_TEST lines identical, hookTimeoutSuites=0, interop5008=open)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…agnostic-messages part B group

- unknown-java-member.test.ts, imports.test.ts, method-body-scope.test.ts, run-call-file-resolution.test.ts,
  use-project-root.test.ts: diagnostic message reads routed through Diagnostic.getMessageString(d)
- imports.test.ts, run-call-file-resolution.test.ts, use-project-root.test.ts, parser.test.ts: missing
  relative-import .js suffixes added (fixes the cachedUseStatements/elements narrowing errors as a
  side effect of restored type resolution, not new guards)
- parser.test.ts: no explicit narrowing needed -- .filter(isVerifyOptions) already narrows once its
  import resolves correctly
- zero type errors in all six files, eslint clean, 299/300 tests pass (1 pre-existing skip), unchanged

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…es, whole suite matches baseline

- All eleven files' diagnostic message reads routed through Diagnostic.getMessageString(d)
- java-qualified-name.test.ts's test.each callback gains its second (description) tuple parameter,
  matching the two-tuple test-case shape it is called with
- functional/unknown-java-member-real-interop.test.ts keeps its shouldRunBBjTests gate and
  production createBBjServices/NodeFileSystem setup unchanged
- zero type errors across all 17 files in this plan, npm run build clean, eslint clean, two
  whole-suite runs both byte-identical to the phase baseline's 11-test FAILED_TEST set

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… test files

- The 13 files named in this plan's default-import error group (workflow-secret-hygiene,
  gradle-wrapper-hygiene, formatter-verifier-tamper, formatter-pins-drift, examples-compile,
  config-path-resolution, compile-request, lsp-protocol-single-copy, example-files,
  conformance-regressions, builtin-library-members, process-runner, cpl-service) switch
  fs/os/path/crypto default imports to the namespace form, matching src's own convention
  under esModuleInterop false.
- examples-compile.test.ts reads its diagnostic message through Diagnostic.getMessageString
  instead of a bare `.message ?? ''` read.
- Orchestrator-assigned addition: test/eslint-disable-directives.test.ts (created after this
  plan was written, flagged UNOWNED in baseline/typecheck-before.txt) gets the same fs/path
  namespace-import fix, since it carries the identical default-import pattern.
- No tsconfig relaxation (esModuleInterop/allowSyntheticDefaultImports) added anywhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… whole tree at zero type errors

- The 9 suffix-only files (composer-commands, addchildwindow-composer, addwindow-composer,
  composer-call-scanner, parser-ambiguity-logging, msgbox-composer, code-action,
  file-path-completion, completion-test) gain the missing .js on their relative imports.
- addwindow-composer-ui.test.ts's and addchildwindow-composer-ui.test.ts's hoisted FakeRange
  constructor now accepts both vscode.Range forms (four numbers, or two Positions with
  trailing undefined args), storing the same four numeric fields either way -- no expected
  value changed, matching production's own new vscode.Range(pos, pos) call sites.
- With this plan's 24 files and the prior fix plans landed, npm run typecheck:test exits 0
  for the whole test tree.
- Whole-suite regression check (two runs): run 2 reproduces baseline/suite-before.txt's
  11-test linking.test.ts FAILED_TEST set exactly; run 1's one extra failure
  (installed-extension-e2e.test.ts, untouched by this plan, already a pre-existing
  FAILED_SUITE in the phase baseline) is confirmed non-regressive contention flakiness.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Build step gets id: build so later steps can key off its outcome
- Lint (npm run lint) and Type-check test tree (npm run typecheck:test)
  run after Build, each gated on !cancelled() && steps.build.outcome == 'success'
- Test step's if: success() || failure() is unchanged, so a lint or
  type failure does not hide test results
- Verified locally: both gates exit 0 on the clean tree; an untracked
  probe file (one unused const, one string-to-number assignment) made
  lint exit 1 (unused-var, naming the probe) and typecheck:test exit 2
  (TS2322 + TS6133, naming the probe); probe deleted, both exit 0 again
- pr-validation.yml and all publish workflows are untouched (diff-checked)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Three consecutive whole-suite runs (default worker count):
  hookTimeoutSuites=0 in all three; numFailedTests=11 with FAILED_TEST
  lines byte-identical to baseline/suite-before.txt in all three;
  durationSec 90/86/83. Each run also shows unexplainedFailedSuites=1
  from the pre-existing installed-extension-e2e.test.ts stale-bundle
  suite failure (0 failed assertions inside it, all skipped/passed) --
  the same known non-regressive entry documented in prior plans in
  this phase (114-02/114-04/114-08/114-09), reproduced identically
  here and unrelated to this plan's changes.
- vitest list --filesOnly matches baseline/files-before.txt plus
  exactly the one new guard test (test/eslint-disable-directives.test.ts)
- bbj-intellij whole suite: ./gradlew cleanTest test BUILD SUCCESSFUL
- bbj-vscode npm run build exits 0
- Phase diff (src, test, config, bbj-intellij/src, .github) carries no
  planning identifiers
- Folded todo 2026-09-20-phase-97-code-review-follow-ups moved to
  completed/ with a resolution note: WR-01..WR-03 closed by 114-03,
  WR-04 by 114-04, the in-IDE progress-bar check is this plan's
  manual checkpoint

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@StephanWald

Copy link
Copy Markdown
Member Author

Probe confirmed: Lint and Type-check test tree both fail, Test still runs. Closing; throwaway.

@StephanWald
StephanWald deleted the throwaway/ci-gate-probe branch September 27, 2026 21:34
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