A real run

A real run

This was a test run. We ran /foghorn:draft on gagoar/typescript-patterns-enforcer for the range v0.5.11..v0.6.0. This page shows the draft. It does not show what the project published.

foghorn icon: a red-orange bell buoy on dark blue water

What GitHub's generator said for the previous release

This is the body of the v0.5.11 release, made by --generate-notes.

It is one line. It names a pull request. It does not say what changed for a user.

## What's Changed
* Keep the new gate rules from tripping the scanner themselves (v0.5.11) by @gagoar in https://github.com/gagoar/typescript-patterns-enforcer/pull/26


**Full Changelog**: https://github.com/gagoar/typescript-patterns-enforcer/compare/v0.5.10...v0.5.11

Source: the v0.5.11 release of gagoar/typescript-patterns-enforcer.

The foghorn draft for v0.6.0

This is the text of the final draft file. We did not change a word of it. The voice is foghorn.

  • Check TypeScript files written through a shell with an advisory Stop hook (#33)

    The mechanical checks ran from a PostToolUse hook, and that hook only sees files that the Edit and Write tools wrote. A .ts file written by a shell heredoc or a script never reached the checks.

    With this release, the plugin also registers a Stop hook. When a session ends, it walks the working directory for .ts and .tsx files modified since the session began and runs the same checks on them. It skips node_modules, .git, dist, build, out, coverage, .next, .turbo and .d.ts files. It is advisory: it reports through systemMessage and always exits 0, so it cannot trap a session.

    New output (a .ts file written through a shell, then the session stops):

    ts-patterns: mechanical violations in TypeScript files changed this session (the edit hook does not see files written through a shell):
    src/list.ts:
      L1:64  no-zero-comparison  `.length` compared with zero: coerce it (`!!x.length`, `!x.length`) (see SKILL.md Core Rule 10).
  • Add six syntactic checks: zero-length comparison, repeated literal, colon-annotated lookup table, fail-open default, String() of an optional chain and void-returning guard (#35)

    The hook now flags six more patterns from the audit of the rules. Each check is syntactic only, because the engine has no type information, so each one matches a narrow shape:

    • no-zero-comparison flags .length compared with zero (> 0, === 0, >= 1, < 1 and the loose forms). It matches .length only.
    • repeated-literal flags the same string or template, at least 8 characters long, written 3 or more times in one file.
    • colon-annotated-lookup flags const x: Record<K, V> = { ... }. Use { ... } as const satisfies Record<K, V> so that keyof typeof x keeps the literal keys. The check ignores an empty {}.
    • fail-open-default flags call() ?? "" and call() ?? 0. The check ignores a property default such as error.status ?? 0, an arithmetic operand and a template placeholder.
    • string-of-optional-chain flags String(a?.b), because String(undefined) is "undefined".
    • void-guard flags a function named guard or assert* that returns void. Declare asserts condition so that the narrowing reaches the caller.

    Original code:

    export function guard(condition: boolean, message: string): void {
      if (!condition) throw new Error(message);
    }

    Old output: none. The hook exited with code 0.

    New output:

    ts-patterns: 1 mechanical violation(s) in guard.ts:
      L1:8  void-guard  `guard` returns void: declare `asserts condition` so the narrowing reaches the caller (see SKILL.md Core Rule 1).  → SKILL.md Core Rule 1 — declare `asserts condition`

    The other five checks follow the same pattern.

    Affects: anyone who runs the plugin on an existing TypeScript codebase. The PostToolUse hook exits with code 2 when it finds a violation. An edit to a file that already contains one of these patterns now goes back to Claude for a fix.

    To check: pipe a hook payload to the engine, as in echo '{"tool_input":{"file_path":"src/a.ts"}}' | node "${CLAUDE_PLUGIN_ROOT}/engine/dist/check.js".

  • Stop the magic-number check from flagging numbers inside a named constant (#35)

    Previously the check flagged every number in an arithmetic expression, even when the expression is the initial value of a const that names the result. The check also flagged a number inside an as const table, although the table is the named constant.

    With this release, the check skips a number in the arithmetic of a const initializer and a number inside an as const literal. This is a deliberate difference from typescript-eslint, which exempts only a bare initializer.

    Original code:

    export const MAX_BYTES = 16 * 1024 * 1024;

    Old output:

    ts-patterns: 3 mechanical violation(s) in magic.ts:
      L1:26  no-magic-numbers  No magic number: 16.  → SKILL.md Core Rule 9 — extract to a named const
      L1:31  no-magic-numbers  No magic number: 1024.  → SKILL.md Core Rule 9 — extract to a named const
      L1:38  no-magic-numbers  No magic number: 1024.  → SKILL.md Core Rule 9 — extract to a named const

    New output: none. The hook exits with code 0.

  • Fold the audit findings into the check skill and the review agent (#32)

    The check skill and the review agent gain the rules that the audit found. No mechanical check covers them. They are: hand-written library shapes, illegal states, fail-open defaults, cast laundering, repeated literals, string boundaries and small items. The review agent has new checklist items 18 to 24.

    Each finding now carries the label correctness or style. A change is done when no correctness finding remains. The skill's review checklist now asks you to print each item marked checked or n/a. It also covers files written through a shell.

What foghorn left out

The range held more changes than the draft shows. foghorn dropped these as internal:

  • the docs redesign
  • the icon
  • the badge
  • the CI gates
  • the version bump

The rule is fixed. A change that only touches the documentation site, the README, badges, artwork, a CI gate, a consistency gate or the version number is internal. foghorn counts the dropped entries and tells you. You can correct a classification before it writes.

What to look for

Each entry names the thing and the change, and links its pull request. Each entry that changed behavior shows what the user sees. The second entry carries an Affects: line and a To check: line, because the change can break someone.

A person still has to read it. The checker looks for an example. It cannot prove that the example is true.