ccppccpp home

Profiles

Compromise 14

Compromise 14.19.x NLP code without pre-14 APIs or invented ones, with explicit selection scope, shared-state ownership, checked patterns and tags, bounded parsing work and package-manager-owned dependencies; any runtime or app shape. Rule IDs CMP-V/C/E/P/A/T/W; NEED TO blocks.

Set this profile

ccpp cpo profile set compromise-14

Inside Claude Code, prefix the command with ! to run it in the session. Downloading a profile needs a Builder or Team plan; listing them does not.

Policies

62 policies, grouped by what they guard.

Untrusted input 3

Requests, downloads and tool output are validated before they reach SQL, a shell, eval or a deserializer.

  • cmp-c14-dynamic-patterns

    CMP-C14 · Values are not interpolated into match syntax (template strings, concatenation): literal words go through .lookup() or validated tokens

  • cmp-c16-html-page-sink

    CMP-C16 · In HTML pages that load compromise, its output (.text(), .out(), .html(), .wrap()) is not assigned to innerHTML/outerHTML or document.write

  • cmp-c16-html-sink

    CMP-C16 · compromise output (.text(), .out(), .html(), .wrap()) reaches HTML only through a text sink or verified escaping

Weakened checks 1

Suppressions, disabled lint or CI steps and relaxed strictness need a reason or the user's approval.

  • cmp-a06-type-suppressions

    CMP-A06 · Type checks on compromise calls are not switched off (@ts-ignore, @ts-expect-error, @ts-nocheck, as any) to hide a wrong API assumption

Error handling 1

Failures are propagated or handled, never swallowed or turned into fake success.

  • cmp-a06-swallowed-failures

    CMP-A06 · Failures around compromise calls are not swallowed (empty catch, catch returning [] / '' / null) to hide a wrong API assumption

Async & concurrency 1

Owned tasks, awaited promises, preserved cancellation and no blocking on event loops.

  • cmp-p09-promise-all

    CMP-P09 · Promise.all around synchronous compromise parsing adds no parallelism; bounded workers do, when measured

Performance & resource bounds 7

Timeouts, bounded retries and fan-out, reused clients, closed resources, no N+1 queries.

  • cmp-p01-reparse

    CMP-P01 · One function parses the same input once and reuses the document (clone it when an independent copy is needed)

  • cmp-p02-result-shape

    CMP-P02 · Ask only for the result needed: .has() for booleans, .matchOne() for the first match, .out('array') for strings

  • cmp-p03-patterns-in-loops

    CMP-P03 · Constant multi-token patterns used inside loops are compiled once with nlp.parseMatch() (compromise re-parses pattern strings on every call)

  • cmp-p04-literal-alternatives

    CMP-P04 · Long plain-word alternatives (a|b|c|…) become one reusable trie lookup when the profile sets maxLiteralAlternatives

  • cmp-p11-speed-entrypoints

    CMP-P11 · Browser code takes only browser-safe compromise-speed helpers (keyPress, lazy): no streamFile/workerPool from compromise-speed/browser or in browserPaths

  • cmp-p12-gpu

    CMP-P12 · No invented GPU/WebGL/WASM acceleration for compromise: no gpu options, backends, packages or methods (14.19 has no GPU backend)

  • cmp-p14-tagger-internals

    CMP-P14 · Size and speed come from supported tiers, not from deleting or replacing tagger internals (world compute, hooks, two.* models)

Architecture & boundaries 6

Declared layers and dependency directions, no import cycles, small modules, explicit dependencies.

  • cmp-a02-cross-file-patterns

    CMP-A02 · A new multi-token match pattern that another compromise module already writes gets one named owner (bounded project scan)

  • cmp-a02-duplicate-patterns

    CMP-A02 · A match pattern repeated in a file gets one named owner (a constant or a parseMatch)

  • cmp-e01-lexicon-per-call

    CMP-E01 · A caller-supplied lexicon is not passed to nlp(text, lexicon): it is added to the shared global lexicon of every later parse

  • cmp-e02-registration-in-loops

    CMP-E02/E05 · Plugins, words, tags and model changes are registered once before processing, not per item or per call

  • cmp-e03-tag-aliases

    CMP-E03 · Custom tag aliases are valid, unique and not shadowed: no spaces or symbols, no alias used twice or taken by a built-in alias, no alias equal to a tag

  • cmp-e03-tag-graph

    CMP-E03 · Custom tags extend real parents: isA/notA name a tag of compromise 14.19, a tag defined in the file or a customTags entry

Language idioms 8

The conventions of the language that keep code predictable for its readers.

  • cmp-c02-selection-scope

    CMP-C02 · The output of a transform is read from the document (doc.text()), not from the returned selection, unless the selection is the contract

  • cmp-c04-view-truthiness

    CMP-C04 · Existence is tested with .has(), .found or .length: a View (even empty) and an output array are always truthy

  • cmp-c05-word-counts

    CMP-C05/C10 · Words are counted and listed from compromise terms, not by splitting its text on spaces

  • cmp-c06-pattern-syntax

    CMP-C06 · Match patterns are compromise term syntax: no nested groups, no character-regex outside /…/ tokens, balanced brackets, real @term methods

  • cmp-c07-unknown-tags

    CMP-C07 · #Tags in patterns resolve against compromise 14.19's tag set and aliases, tags defined in the file, or the profile's customTags

  • cmp-c08-capture-groups

    CMP-C08 · A pattern with [capture] brackets is read through .groups(name) or the group argument, not as if brackets narrowed the match

  • cmp-p05-sweep-result

    CMP-P05 · .sweep(net) returns { view, found }: its result is destructured or read through .view, never chained as a View

  • cmp-v12-manual-money

    CMP-V12/V14/A03 · Numbers and money are not re-parsed from compromise text (parseFloat, Number, x100 '%'): use .get(), .add(), .toPercentage()…

Caching 1

Cache scopes, lifetimes and invalidation stated explicitly.

  • cmp-p06-cache-mutation

    CMP-P06 · A document frozen with .cache() is .uncache()d before it is transformed (cached matches go stale)

Versions & deprecated APIs 9

Code matches the installed version, without removed, renamed or deprecated APIs.

  • cmp-v01-installed-version

    CMP-V01/V02/W07 · At session start, Claude learns the resolved compromise version and plugins, whether this 14.19 profile applies, and where the version-matched docs are

  • cmp-v02-unknown-statics

    CMP-V02 · nlp.* calls exist in compromise 14.19 or a loaded plugin (no invented statics such as nlp.normalize, nlp.parse, nlp.sentences)

  • cmp-v03-import-paths

    CMP-V03/V01 · compromise is imported through its package exports: no src/builds/types internals, no type-only subpaths at run time, no v12/v13 plugins

  • cmp-v04-build-tier

    CMP-V04 · Code uses only what its compromise tier provides: no named selections on compromise/two, no tags or tagger methods on compromise/one or nlp.tokenize()

  • cmp-v05-compat-helpers

    CMP-V05/V08/V15 · Current spellings over retained compatibility helpers: .eq(n) over View .get(n), .json()[n] over .json(n), .json() over .data(), .compute('tagger'), .numbers(), DateOptions

  • cmp-v06-number-arrays

    CMP-V06 · .get() on numbers/money/percentages returns an array: it is not used as a number (arithmetic, comparison, toFixed)

  • cmp-v07-removed-apis

    CMP-V07 · No APIs removed by compromise 14: .parent(s), .lists(), .segment(), .export(), nlp.clone/load, function plugins, array patterns, toParticiple/toPossessive/hasPlural

  • cmp-v10-compute-names

    CMP-V10 · .compute(name) names a computation the installed compromise or an official plugin registers (unknown names only log 'no compute')

  • cmp-v15-plugin-methods

    CMP-V04/V15 · Plugin methods (.dates(), .ngrams(), .syllables(), .paragraphs(), payloads, nlp.keyPress…) are used only with the plugin installed

Logging & observability 1

Structured logs, bounded metric labels, no debug prints left in production code.

  • cmp-v11-debug-output

    CMP-V11 · Tracing is targeted and switched off: no .debug(object), no .debug()/nlp.verbose() left in non-test code

Dependencies & toolchain 17

Packages change through the package manager, lockfiles stay consistent and the project's tools are used.

  • cmp-v01-install-specs

    CMP-V01/W03 · Installing compromise at a version outside this profile's release (another major, an older 14 minor, the stale `next` tag) is refused

  • cmp-v01-legacy-plugins

    CMP-V01/V07 · No v12/v13-era compromise plugins (compromise-numbers, -sentences, -adjectives, -export, -html, -ngrams, -syllables…) are installed

  • cmp-v01-resolved-version

    CMP-V01 · After an install that named compromise, the resolved compromise is still on this profile's release

  • cmp-w01-init-over-project

    CMP-W01 · No package-manager initializer (npm/pnpm/yarn/bun init, npm create) runs in a directory that already has a package.json

  • cmp-w01-package-manager

    CMP-W01 · Dependencies are installed with the project's package manager (packageManager field, lockfile)

  • cmp-w01-second-lockfile

    CMP-W01 · No second lockfile next to another package manager's lockfile

  • cmp-w02-hand-written-manifest

    CMP-W02 · A new package.json without dependencies is initialized with the package manager

  • cmp-w02-new-manifest

    CMP-W02/W03 · A new package.json comes from the package-manager initializer (or a generator), and gets its dependencies from the package manager

  • cmp-w03-manual-dependency-edit

    CMP-W03 · Dependencies change through the package manager (add/remove/update), never by editing package.json by hand

  • cmp-w03-package-manager-call

    Records the tool calls that run a package manager (they may rewrite package.json and lockfiles; CMP-V01/W03/W04)

  • cmp-w03-version-lookups

    CMP-W03 · Registry version lookups are not a step before installing

  • cmp-w03-version-pins

    CMP-W03 · Packages are installed by name: no guessed exact version, no @latest, no --save-exact without a reason

  • cmp-w04-hand-edited-lockfile

    CMP-W04 · Lockfiles are written by the package manager only (no hand edit, no script rewriting them)

  • cmp-w04-stale-lockfile

    CMP-W04 · A turn that changes package.json dependencies also updates the lockfile next to it (once per stop)

  • cmp-w05-vendored-builds

    CMP-W05 · compromise builds are not downloaded or copied into the project by hand (curl/wget from a CDN, cp from node_modules): the package manager provides them

  • cmp-w06-invented-cli

    CMP-W06 · No compromise CLI is invoked: the package declares no bin (npx/bunx/pnpm dlx compromise, a `compromise` command)

  • cmp-w06-manifest-cli

    CMP-W06 · package.json scripts do not call a compromise binary (compromise declares no bin)

Tests 4

Tests assert behavior, stay deterministic and are not removed or skipped silently.

  • cmp-c15-exact-tag-arrays

    CMP-C15 · Tests and code compare tag membership (has('#Tag'), tags.includes), not exact incidental tag arrays that change with the hierarchy

  • cmp-t01-mocked-compromise

    CMP-T01 · Tests exercise compromise itself: no jest/vi/bun module mocks or stubs replacing compromise or its plugins

  • cmp-t03-fromspec-defaults

    CMP-T03 · nlp.fromSpec() results are not used as validation: .failures needs a failures option, tag checks need tags: 'use' (defaults ignore both)

  • cmp-t04-testspec-result

    CMP-T04 · testSpec() success is read from .failures (or throwError), never from the truthiness, .found, .length or text of the returned View

Completion evidence 3

A turn ends with its checks run and passing; claims of success need proof after the last edit.

  • cmp-p15-measurement-ledger

    Records that the turn ran a measurement (benchmark, profiler, timing script) for CMP-P15

  • cmp-p15-performance-claims

    CMP-P15 · A turn that changed compromise code does not claim a speed, memory or accuracy gain without a measurement in the turn (once per stop)

  • cmp-turn-baseline

    Records the work tree when a prompt starts: the baseline of the compromise end-of-turn checks (CMP-W04, P15)