/**
 * Version-pinned parity drift detector (PR-1, mmnto-ai/totem#2069).
 *
 * First detection slice on top of the merged manifest-parser skeleton (#2070).
 * Senses ONE tractability class — `version-pinned` — and only its DEPS subset
 * (the four `@mmnto/*` cohort-floor contracts: `mmnto-cli-version`,
 * `mmnto-totem-version`, `mmnto-mcp-version`,
 * `mmnto-pack-rust-architecture-version`). The verdict is **pin currency only**
 * (Tenet 20 claim-class bound): does the consumer's `@mmnto/*` pin resolve to
 * the current published cohort floor? It NEVER asserts semantic / file-content
 * drift — that would over-claim the `version-pinned` class.
 *
 * Layering: core must NOT import cli's `DiagnosticResult` (wrong dependency
 * direction). This module returns a core-local `ParityContractVerdict`; the CLI
 * (`doctor-parity.ts`) maps it to `DiagnosticResult` and owns the
 * `--strict`/`blocking` fail-promotion. The detector itself returns ONLY
 * `pass`/`warn`/`skip` — never `fail` — so the gate edge stays a CLI concern.
 *
 * Design invariants (mirroring `parity-manifest.ts` + `strategy-resolver.ts`):
 *   - **Honest-absent (Tenet 14):** absence is never an error. Not-a-consumer,
 *     floor-unresolvable, or a doctrine pin this slice doesn't handle → `skip`
 *     (the manifest's `-` "cohort permits absence"). An *applicable* consumer
 *     missing an expected pin is also `skip` while the manifest is scaffold, but
 *     kept DISTINCT (expected-but-absent → a `warn` once the consumers lists are
 *     verified) so the `consumers` field still catches the missing case. Never a
 *     fabricated verdict.
 *   - **NEVER networks:** the cohort floor is derived LOCALLY — self-in-tree
 *     (the totem monorepo at the current git root), a `../totem` sibling
 *     checkout, or — for a package totem doesn't publish — the contract's own
 *     canonical-source repo (e.g. `../totem-strategy`). None reachable →
 *     honest-absent `skip` with a reason.
 *   - **Side-effect-free / no caching:** every call reads from scratch. Each
 *     filesystem / git seam is injectable so tests drive synthetic fixtures.
 *   - **Never throws:** every read failure degrades to a `skip`/`warn` verdict;
 *     the sensor must never crash the doctor pipeline.
 */
import { type ParityContract, type ParitySense } from './parity-manifest.js';
import { type StrategyResolverOptions, type StrategyRootStatus } from './strategy-resolver.js';
/**
 * Parity dimension for toolchain-version rows. A row in this dimension that
 * resolves NO deps package (e.g. `pnpm-engine-version`) pins its engine via the
 * consumer's `packageManager` field instead — the toolchain reader senses it
 * (mmnto-ai/totem#2115). `mmnto-cli-version` shares this dimension but resolves
 * `@mmnto/cli`, so it stays on the deps path.
 */
export declare const TOOLCHAIN_DIMENSION = "toolchain-version";
/**
 * Core-local per-contract verdict. The CLI renders this directly (core cannot
 * depend on cli's `DiagnosticResult`/`CheckStatus`). The verdict vocabulary is
 * intentionally WIDER than the shared `CheckStatus` so the parity sensor can
 * honor the round's verdict-state split (mmnto-ai/totem#2073 req #1 — don't
 * collapse to a binary pass/fail) without rippling `CheckStatus` across every
 * unrelated doctor check:
 *   - `pass`    — verified equal / current.
 *   - `warn`    — drift (sensor-not-gate default; the CLI promotes a `warn` from
 *                 a `blocking: true` contract to `fail` ONLY under `--strict`).
 *   - `info`    — an intentional, attested fork (req #7) — NEVER gated/promoted.
 *   - `unknown` — the Stale-Doctor-Paradox state: the canonical could not be
 *                 resolved, so the doctor can prove neither drift NOR currency.
 *                 NEVER rendered as `pass` (no self-certification); NEVER gated.
 *   - `skip`    — not-applicable / cohort-permits-absence / out of this slice.
 *
 * `fail` stays in the union as the CLI-edge promotion target, but a DETECTOR
 * never emits it (the gate edge is a CLI concern, unchanged from PR-1).
 */
export interface ParityContractVerdict {
    status: 'pass' | 'warn' | 'fail' | 'info' | 'unknown' | 'skip';
    message: string;
    remediation?: string;
}
/** Test seams for {@link deriveCohortRepoId} (mirrors `StrategyResolverOptions`). */
export interface DeriveCohortRepoIdOptions {
    /**
     * Pre-resolved git `origin` remote URL. Production callers omit it and the
     * helper shells out via `git remote get-url origin`. When provided (even as
     * `undefined`, signalling "no remote"), the shell-out is skipped.
     */
    remoteUrl?: string;
    /**
     * Full override of the remote reader. Takes precedence over `remoteUrl`. A
     * throwing reader is swallowed (git failure → fall through), so passing one
     * that throws exercises the no-network / no-throw path.
     */
    readRemote?: (cwd: string) => string | undefined;
    /** Test seam — production callers omit and the helper invokes `resolveGitRoot(cwd)`. */
    gitRoot?: string | null;
}
/**
 * Derive the current repo's cohort id (e.g. `totem-status`) used to evaluate a
 * contract's `consumers` applicability. Precedence:
 *   1. git `origin` remote — `…mmnto-ai/<name>(.git)?` → `<name>`.
 *   2. `package.json` `name` basename (scope stripped) — `@mmnto/totem-status`
 *      → `totem-status`.
 *   3. git-root directory basename.
 *
 * Returns `undefined` only when nothing resolves. NEVER throws and NEVER
 * networks beyond the local `git remote get-url` read (which is swallowed on
 * failure — git being unavailable is a routine fall-through, not an error).
 */
export declare function deriveCohortRepoId(cwd: string, options?: DeriveCohortRepoIdOptions): string | undefined;
/**
 * Resolve the `@mmnto/*` (or vendor) package name a deps/vendor contract pins.
 * Precedence:
 *   1. **explicit `package:` field** (mmnto-ai/totem-strategy#517) — the
 *      machine-parseable name, derive-not-guess. Preferred when present.
 *   2. **canonical-source path locator** — when `canonicalSource` carries a
 *      `:path/to/package.json` segment (e.g. `mmnto-cli-version`'s
 *      `mmnto-ai/totem:packages/cli/package.json#version`), read the `name`
 *      from that package.json under `floorRoot`. Authoritative — no id guess.
 *   3. **id convention** — `mmnto-<x>-version` → `@mmnto/<x>` (fallback until all
 *      contracts carry `package:`).
 *
 * Returns `undefined` for contracts with no `package:`, no path locator, and an
 * id that doesn't match the convention (e.g. `governance-doctrine`, `gate-config`)
 * so ONLY the contracts this slice handles resolve a name; the CLI keeps the rest
 * as `skip` stubs.
 *
 * @param floorRoot Optional root the canonical-source path locator anchors at
 *                  (the resolved cohort-floor repo). Omit when only `package:` /
 *                  the id convention is wanted.
 */
export declare function packageNameForContract(contract: ParityContract, floorRoot?: string): string | undefined;
/**
 * Honest-absent cohort-floor resolution outcome (discriminated union, mirroring
 * `StrategyRootStatus`):
 *   - `resolved: true`  — `version` is the floor; `source` tags WHICH local
 *     layer supplied it (`self-in-tree` | `sibling`).
 *   - `resolved: false` — `reason` is an agent-surfacing string (e.g. clone the
 *     monorepo as a sibling). The sensor renders this as a `skip`.
 */
export type CohortFloorStatus = {
    resolved: true;
    version: string;
    source: 'self-in-tree' | 'sibling' | 'canonical-source';
} | {
    resolved: false;
    reason: string;
};
/**
 * Resolve the "current published version" cohort floor for `packageName`,
 * derived LOCALLY (NEVER networks), in precedence order:
 *   (a) **self-in-tree** — the current git root IS the canonical-source repo
 *       (the totem monorepo): glob `<gitRoot>/packages/*​/package.json`, find
 *       the one whose `name === packageName`, read its `version`.
 *   (b) **sibling** — `<gitRoot>/../totem` exists as a directory: glob its
 *       `packages/*​/package.json` the same way.
 *   (c) **canonical-source repo** — when `canonicalSource` names a repo totem
 *       does NOT publish (e.g. `mmnto-ai/totem-strategy` for
 *       `@mmnto/strategy-doctrine`), the floor lives in that repo's
 *       `packages/*`, not totem's. Locate it via `resolveStrategyRoot`
 *       (env / config / `../totem-strategy` sibling) and glob the same way.
 *       Without this, strategy-published rows resolve `skip` instead of the
 *       consumer-side `pass`/`warn` (mmnto-ai/totem#2108).
 *   (d) **honest-absent** — none reachable → `{ resolved: false, reason }`.
 *
 * NEVER fabricates a floor and NEVER fetches (`resolveStrategyRoot` is local
 * fs only). Anchors at `gitRoot`, not cwd (mirroring `strategy-resolver.ts`).
 * Read failures within the glob are swallowed per-file so one corrupt
 * package.json can't crash the resolver.
 *
 * The floor is keyed structurally on `packageName` (the matching
 * `packages/*​/package.json` `name`), NOT on the consumer's cohort id — a
 * misderived repoId can't mask a genuine in-tree floor.
 */
export declare function resolveCohortFloor(packageName: string, gitRoot: string, canonicalSource?: string | null): CohortFloorStatus;
/** Test seams + context for {@link detectVersionPinnedContract}. */
export interface DetectVersionPinnedContext {
    /** The consumer repo to read `package.json` / `node_modules` from. */
    cwd: string;
    /** The git root to anchor cohort-floor resolution at (NOT cwd — mirrors the resolver). */
    gitRoot: string;
    /** The current repo's cohort id (from {@link deriveCohortRepoId}) for `consumers` applicability. */
    repoId?: string;
    /**
     * Package name pre-resolved by the caller (the CLI resolves it once for
     * routing — {@link packageNameForContract}). When provided, the detector skips
     * re-resolving it (avoids a duplicate locator package.json read). Omit and the
     * detector resolves it itself.
     */
    packageName?: string;
    /**
     * Test seam — override the consumer package.json read. Production callers omit
     * it and the detector reads `<cwd>/package.json`.
     */
    readPackageJson?: (absPath: string) => PackageJsonShape | undefined;
}
/**
 * Minimal package.json shape the detector reads. Deliberately loose — the file
 * is untrusted on-disk JSON, so every field is optional + runtime-checked.
 */
export interface PackageJsonShape {
    name?: string;
    version?: string;
    dependencies?: Record<string, string>;
    devDependencies?: Record<string, string>;
    optionalDependencies?: Record<string, string>;
    /** Corepack engine pin (`<name>@<version>(+<hash>)?`) — read by the toolchain reader (mmnto-ai/totem#2115). */
    packageManager?: string;
}
/**
 * Detect drift for ONE `version-pinned` deps contract. Returns a
 * `ParityContractVerdict`:
 *   - **pass** — the consumer's resolved-installed `@mmnto/*` version is ≥ the
 *     cohort floor (current).
 *   - **warn** — installed < floor (stale pin). Sensor-not-gate default: the
 *     detector returns `warn` even for a `blocking` contract; the CLI promotes
 *     to `fail` only under `--strict`.
 *   - **skip** — not-a-consumer / pin not declared / floor unresolvable / not a
 *     deps contract this slice handles / unparseable range (honest-absent).
 *
 * NEVER emits `fail` (CLI-edge concern). NEVER throws (read failures degrade to
 * `skip`). NEVER networks (floor is local-only). NEVER asserts content drift
 * (claim-class bound to pin currency).
 */
export declare function detectVersionPinnedContract(contract: ParityContract, ctx: DetectVersionPinnedContext): ParityContractVerdict;
/**
 * Inputs + test seams for {@link detectManualAttestationContract}. The sub-class
 * discriminant (`package:`) + the canonical source are read DIRECTLY off the
 * `contract` argument (single source of truth) — the context carries only the
 * consumer-local read seams + the reserved attestation date.
 */
export interface DetectManualAttestationContext {
    /** The consumer repo to read `package.json` from (the vendor-SDK pin read). */
    cwd: string;
    /** The current repo's cohort id (from {@link deriveCohortRepoId}) for `consumers` applicability. */
    repoId?: string;
    /**
     * OPTIONAL local attestation date (ISO-8601), sourced from the manifest's
     * `last-attested:` field (strategy#540 shipped the producer; the doctor wires
     * it through per mmnto-ai/totem#2125). When present the message reports it,
     * but the VERDICT stays `info` regardless — staleness is a message
     * refinement, NEVER a status change (manual-attestation never warns).
     */
    attested?: string;
    /**
     * Test seam — override the consumer package.json read. Production callers omit it
     * and the detector reads `<cwd>/package.json`. Invoked ONLY on the vendor-SDK
     * path; the doctrine-row path performs no read at all (a throwing seam proves it).
     *
     * Scope note (Greptile review on mmnto-ai/totem#2080): this seam covers ONLY the
     * top-level consumer package.json read (the declared-range lookup). The
     * installed-version half (`resolveInstalledVersion`) reads the REAL `node_modules`
     * ancestry and, for any VALID range, falls back to `semver.minVersion(range)` — so
     * `"installed: unresolved"` arises solely from an UNPARSEABLE range, never from
     * absent node_modules. A test injecting this seam with a valid range but no on-disk
     * install therefore sees the minVersion fallback BY DESIGN. The boundary is shared
     * verbatim with `detectVersionPinnedContract` (same `resolveInstalledVersion`, same
     * seam scope) — deliberately not widened here to keep the two detectors aligned.
     */
    readPackageJson?: (absPath: string) => PackageJsonShape | undefined;
}
/**
 * Detect "drift" for ONE `manual-attestation` contract — the claim-class with NO
 * mechanical sensor (Tenet 19). The verdict ceiling is **`info` or `skip` ONLY**:
 * the doctor may SURFACE the tracked coupling/doctrine + FLAG staleness, but may
 * NEVER assert drift (`warn`), failure (`fail`), currency (`pass`), or an
 * unprovable-canonical (`unknown`) — there is no canonical to prove against. This
 * is the manifest's "surfaces last-attested + flags staleness only, NEVER fails"
 * contract, claim-class-tighter than the mechanical / version-pinned detectors
 * (which may `warn`). The `info`/`skip` ceiling means the contract can never enter
 * the CLI's `blockingDriftIds`, so it is structurally incapable of failing even
 * under `--strict`.
 *
 * Two sub-classes, discriminated by the contract's `package:`:
 *   - **vendor-SDK coupling** (`packageName` set — `@google/genai`,
 *     `@anthropic-ai/sdk`): reads the consumer's LOCAL pin (declared range +
 *     resolved installed version, reusing the version-pinned machinery) and
 *     surfaces it as `info` — NO cohort floor exists, so NO currency claim is made
 *     (Tenet 16, attest-don't-enforce). The DURABLE manual-attestation case.
 *   - **doctrine row** (`packageName` unset — `governance-doctrine`,
 *     `agent-memory-doctrine`): `canonicalSource` is a cross-repo AGENTS.md the
 *     local-read-only doctor must NOT fetch. Emits a pure `info` doctrine-currency
 *     surface from the contract fields with ZERO on-disk I/O. TRANSIENT — graduates
 *     to version-pinned when doctrine-distribution ships (strategy#511 / #526).
 *
 * NEVER throws (reads degrade to skip), NEVER networks, NEVER reads the cross-repo
 * `canonicalSource`, and NEVER emits `pass`/`warn`/`fail`/`unknown`.
 */
export declare function detectManualAttestationContract(contract: ParityContract, ctx: DetectManualAttestationContext): ParityContractVerdict;
/**
 * A consumer's hand-added fork/override marker (mmnto-ai/totem#2073 req #7).
 * When present on a managed-block artifact, a content difference reads as an
 * INTENTIONAL, attested fork (`info`) rather than drift (`warn`). Sibling to —
 * NOT merged with — Proposal 292's publisher-generated currency sidecar
 * (strategy-claude 2026-06-04T0158Z: shared `totem:` namespace + `attested`
 * (ISO-8601) / `owner` field conventions, but separate author + lifecycle).
 *
 * Shape: `<!-- totem:fork reason="…" owner="…" attested="YYYY-MM-DD" -->`.
 * Every attribute is optional — a bare `totem:fork` marker still flags a fork.
 */
export interface ForkMarker {
    reason?: string;
    owner?: string;
    /** ISO-8601 date the fork was last attested (as authored; not validated here). */
    attested?: string;
}
/** The marker pair delimiting a managed block within a distributed artifact. */
export interface ManagedBlockMarkers {
    start: string;
    end: string;
}
/** Inputs + test seams for {@link detectMechanicalContract}. */
export interface DetectMechanicalContext {
    /**
     * The canonical managed-block content, ALREADY extracted from the running
     * `@mmnto/cli`'s own template by the CLI (core cannot import init-templates —
     * wrong dependency direction). `undefined`/empty signals the canonical was
     * unresolvable → `unknown` (the Stale-Doctor-Paradox guard).
     */
    canonicalBlock: string | undefined;
    /** Absolute path to the consumer artifact on disk (e.g. `.claude/skills/<n>/SKILL.md`). */
    consumerPath: string;
    /** The marker pair delimiting the managed block in BOTH canonical + consumer. */
    markers: ManagedBlockMarkers;
    /**
     * Running `@mmnto/cli` provenance for the req-#5 self-report. The
     * Stale-Doctor-Paradox includes the doctor ITSELF being a shadowed/stale
     * binary supplying a stale in-process canonical; surfacing which binary
     * computed the verdict keeps the skills verdict honest about its own
     * provenance (a one-line self-report, not a resolver cascade — that's the
     * on-disk hooks case).
     */
    binary?: {
        version: string;
        path: string;
    };
    /**
     * Test seam — override the consumer file read. Production callers omit it and
     * the detector reads `<consumerPath>` (UTF-8); a read failure is honest-absent.
     */
    readFile?: (absPath: string) => string | undefined;
}
/**
 * Normalize a managed block for content comparison (req #3): CRLF / lone-CR → LF,
 * strip trailing whitespace per line, and trim leading/trailing blank lines. Two
 * blocks that differ ONLY in line endings or trailing whitespace — the win32
 * checkout false-positive class — normalize equal.
 */
export declare function normalizeManagedBlock(block: string): string;
/**
 * Extract the content BETWEEN the first `markers.start` and the first following
 * `markers.end`. Returns undefined when either marker is absent (an unmanaged or
 * marker-stripped file). The markers themselves are excluded from the result.
 */
export declare function extractManagedBlock(content: string, markers: ManagedBlockMarkers): string | undefined;
/**
 * Parse a `<!-- totem:fork reason="…" owner="…" attested="…" -->` marker from
 * anywhere in `content`. Whitespace-tolerant (mirrors `REFLEX_VERSION_RE`).
 * Returns undefined when no marker is present; each attribute is independently
 * optional, so a bare `<!-- totem:fork -->` returns an empty marker object
 * (still a fork signal). The attribute patterns are fixed literals (no dynamic
 * RegExp) and linear (no nested quantifiers) — ReDoS-safe.
 */
export declare function parseForkMarker(content: string): ForkMarker | undefined;
/**
 * Short content hash (sha256, first 12 hex chars) of a normalized block, for the
 * verdict's machine-readable record (req #6). The hash IS the content-equality
 * evidence — bytes, never prose-parsing (req #2's spirit).
 */
export declare function hashManagedBlock(normalized: string): string;
/**
 * Detect drift for ONE mechanical managed-block contract (the #2073 mechanical
 * skills slice). Compares the consumer's installed managed-block against the
 * running `@mmnto/cli`'s own canonical block (passed in by the CLI), normalized
 * for line-endings + trailing whitespace (req #3) and content-hashed (req #6).
 * Honors the verdict-state split (req #1) + the fork marker (req #7):
 *
 *   - `pass`    — normalized blocks equal.
 *   - `warn`    — blocks differ, no fork marker (drift); reports both short hashes.
 *   - `info`    — blocks differ AND a `totem:fork` marker is present (attested fork).
 *   - `unknown` — canonical unresolvable (the doctor may itself be stale/shadowed);
 *                 never self-certify as `pass`.
 *   - `skip`    — consumer artifact not installed (cohort permits absence).
 *
 * NEVER throws (reads degrade), NEVER networks (canonical is in-process), NEVER
 * emits `fail` (the gate edge is a CLI concern, unchanged from PR-1).
 */
export declare function detectMechanicalContract(ctx: DetectMechanicalContext): ParityContractVerdict;
/** Inputs + test seams for {@link detectGeneratedArtifactContract}. */
export interface DetectGeneratedArtifactContext {
    /**
     * The canonical artifact content, REGENERATED by the CLI from the running
     * `@mmnto/cli`'s own generator (e.g. `buildPrePushHook(getFallbackCommand(repo), tier)`)
     * for THIS repo's package-manager + tier — never a frozen string (a pnpm-flavored
     * canonical would false-positive an npm consumer). `undefined` signals the
     * generator could not produce it → `unknown` (the Stale-Doctor-Paradox guard).
     */
    canonicalContent: string | undefined;
    /** Absolute path to the consumer artifact on disk (e.g. `.git/hooks/pre-push`). */
    consumerPath: string;
    /**
     * The totem ownership/presence marker substring (e.g. `[totem] pre-push hook`).
     * Its ABSENCE in a present file means the artifact is a pure user file with no
     * totem content → `skip` (cohort permits absence), NOT drift. This presence
     * semantics is why generated artifacts need their own detector vs the skills
     * managed-block model — there, a markerless file IS stripped-drift.
     */
    ownershipMarker: string;
    /**
     * Optional end marker bracketing the totem-owned region. post-merge / post-checkout
     * carry one; pre-commit / pre-push do not. When present, a totem block APPENDED
     * into a user-modified hook can be isolated for comparison; when absent, an
     * appended block degrades to `unknown` (cannot prove drift — claim-class-tight).
     */
    endMarker?: string;
    /**
     * Running `@mmnto/cli` provenance for the req-#5 self-report (Stale-Doctor-Paradox:
     * a shadowed/stale doctor would regenerate a stale canonical — surface which binary
     * computed the verdict). The full ADR-072 resolver cascade lives in the CLI's
     * canonical-generator resolution; the detector just reports the resolved binary.
     */
    binary?: {
        version: string;
        path: string;
    };
    /**
     * Human-facing noun for this artifact class in the absence/drift copy (e.g.
     * `'git hook'`, `'SessionStart hook'`). Defaults to `'artifact'`. Threaded so the
     * detector — now shared across git hooks AND the static SessionStart hooks — never
     * hardcodes one class's terminology (Greptile review on mmnto-ai/totem#2082).
     */
    artifactLabel?: string;
    /**
     * The install/repair command the remediation points at — `'totem hook install'` for
     * git hooks, `'totem init'` for SessionStart hooks. Defaults to `'totem init'` so a
     * SessionStart absence/drift is never told to run the git-hook installer.
     */
    installCommand?: string;
    /** Test seam — override the consumer file read. Production callers omit it. */
    readFile?: (absPath: string) => string | undefined;
}
/**
 * Detect drift for ONE generated-artifact contract (the mmnto-ai/totem#2073 hooks
 * slice) — the git hooks (`pre-commit` / `pre-push` / `post-merge` / `post-checkout`),
 * which the CLI regenerates per-repo via `build*Hook(getFallbackCommand(repo), tier)`
 * so the canonical matches THIS repo's package manager + tier (no frozen-string
 * false-positive). Honors the verdict-state split + the fork marker, and detects
 * STALE-VERSION drift (a hook frozen at an older generator's output differs from
 * today's regenerated canonical → `warn` — the detection half of mmnto-ai/totem#1854):
 *
 *   - `pass`    — the totem-owned content equals the regenerated canonical.
 *   - `warn`    — an owned hook drifted (incl. a stale pre-mmnto-ai/totem#2053 resolve order); reports both hashes.
 *   - `info`    — drift AND a `totem:fork` marker — an attested intentional fork.
 *   - `unknown` — canonical unregenerable, OR a totem block appended inside a user
 *                 hook with no end marker to isolate it (cannot prove drift).
 *   - `skip`    — hook absent, OR present but not totem-managed (cohort permits absence).
 *
 * NEVER throws (reads degrade), NEVER networks (canonical is in-process), NEVER
 * emits `fail` (the gate edge is a CLI concern, unchanged from PR-1).
 */
export declare function detectGeneratedArtifactContract(ctx: DetectGeneratedArtifactContext): ParityContractVerdict;
/**
 * The probe sub-kinds this slice ships (the two deliverable-1 rows):
 *   - `mcp-registration` — does `.mcp.json` register a totem MCP server? The
 *     PRESENT rung of `knowledge-search-access` ("a working query path exists
 *     from this agent surface"). The usable rung (a live bounded search exec)
 *     is deliberately NOT shipped: real `totem search` embeds the query via a
 *     cloud API, which a §12.5 never-network probe cannot run — flagged to
 *     strategy with the row-downshift question.
 *   - `settings-floor` — does `.claude/settings.json` suppress the governance
 *     floor (`claude-settings-minimum-capability`)? Canonical-at-intent-altitude
 *     (296 §6(c)): the canonical is a minimum-capability CONTRACT, so the probe
 *     senses explicit SUPPRESSION only — an absent file (or any unrelated
 *     content) is `pass`; the doctor never prescribes settings content.
 */
export type CapabilityProbeKind = 'mcp-registration' | 'settings-floor';
/** Inputs + test seams for {@link detectCapabilityProbeContract}. */
export interface DetectCapabilityProbeContext {
    kind: CapabilityProbeKind;
    /** Absolute path of the probed file (`.mcp.json` / `.claude/settings.json`). */
    consumerPath: string;
    /**
     * `settings-floor` only: absolute path to `.mcp.json`, read to DERIVE the
     * totem MCP server names cross-checked against `disabledMcpjsonServers`
     * (derive-not-hardcode, Tenet 20). Absent/unreadable → nothing to cross-check
     * (the MCP half of the floor is vacuous; the hooks half still applies).
     */
    mcpJsonPath?: string;
    /** The state-level THIS probe proves by design (`present` for both kinds today). */
    probedLevel: ParitySense;
    /**
     * The row's declared `senses:` (open string off the contract). When it names
     * a RECOGNIZED level stronger than `probedLevel`, a would-be `pass` is capped
     * at `unknown` — the green-halo invariant at probe altitude: a presence-PASS
     * must never render as a capability-PASS (296 §6(a)3 / strategy#591).
     */
    declaredSenses?: string;
    /** Test seam — override the file read. Production callers omit it. */
    readFile?: (absPath: string) => string | undefined;
}
/**
 * Detect ONE capability-probe contract (`manifestation: capability-probe`,
 * 296 §6(a)2). Deterministic, local-read-only, NEVER networks, NEVER throws,
 * and NEVER emits `fail` (CLI edge owns promotion) or `info` (probes decide,
 * they do not attest — "sense-only" means no actuator, not an info ceiling;
 * the 296 §6(a)4 settled vocabulary is pass/warn/skip/unknown).
 */
export declare function detectCapabilityProbeContract(ctx: DetectCapabilityProbeContext): ParityContractVerdict;
/**
 * A parsed `<!-- totem:<token> role="…" seat="…" declared="…" -->` declaration
 * marker (Prop 305 §3 agent-bus class). Every attribute is independently
 * optional at PARSE time; the VALIDITY rule (a real declaration binds BOTH a
 * role and a seat) lives in {@link detectDeclaredContract} so a missing
 * attribute surfaces as a NAMED why-not, never a silent drop (fail loud, Tenet 4).
 */
export interface DeclarationMarker {
    role?: string;
    seat?: string;
    /** ISO-8601 date the declaration was authored (as authored; not validated here). */
    declared?: string;
}
/**
 * Parse a `<!-- totem:<token> key="value" … -->` declaration marker from
 * anywhere in `content`. Modeled on {@link parseForkMarker}: dotAll + whitespace
 * tolerant, `.*?` non-greedy + bounded by the first `-->` (linear, no nested
 * quantifiers → ReDoS-safe). `token` is the full bare marker name (e.g.
 * `totem:agent-bus`) and is regex-escaped via the shared `escapeRegex`, so a
 * `:` or any metachar is matched as a literal, never as a live pattern (the
 * token is code-owned by the CLI registry, but escaping keeps it robust
 * regardless). The FIRST marker for `token` wins — duplicates are ignored, the
 * same single-match posture as {@link parseForkMarker}. The token must be
 * followed by whitespace or `-->` (a lookahead, not `\b`), so a token never
 * prefix-matches a longer sibling (`totem:agent-bus` vs `totem:agent-bus-v2`)
 * and non-word-char-ending tokens need no special casing. Returns undefined
 * when no marker for `token` is present.
 */
export declare function parseDeclarationMarker(content: string, token: string): DeclarationMarker | undefined;
/** Inputs + test seams for {@link detectDeclaredContract}. */
export interface DetectDeclaredContext {
    /** Absolute path of the file that carries the declaration marker (AGENTS.md). */
    filePath: string;
    /** The bare `totem:<token>` marker name the declaration is authored under (e.g. `totem:agent-bus`). */
    markerToken: string;
    /** Test seam — override the file read. Production callers omit it. */
    readFile?: (absPath: string) => string | undefined;
}
/**
 * Detect ONE `manifestation: declared` contract (Prop 305 §3 agent-bus class).
 * A declaration SURFACE — the repo AUTHORS the binding itself in a file
 * (AGENTS.md) via a `<!-- totem:<token> role="…" seat="…" -->` HTML-comment
 * marker rather than installing a managed block. This sensor claims DECLARATION
 * PRESENCE ONLY; whether the declared bus actually EXECUTES its duties is
 * adherence-class (Tenet 19 / Prop 305 §3.5) and is NEVER inferred from this row.
 *
 * Deterministic, local-read-only, NEVER networks, NEVER throws, NEVER emits
 * `fail` (CLI edge owns promotion), and NEVER `warn`/`fail` on absence — an
 * undeclared repo is honest-absent (`skip`), the row's own "honest-absent until
 * a repo declares" semantics, not drift.
 *
 *   - `pass` — marker present with BOTH role + seat parsed (a well-formed binding).
 *   - `skip` — file absent, marker absent, or the marker is missing role/seat
 *              (the why-not names the missing attribute — fail loud, Tenet 4).
 */
export declare function detectDeclaredContract(ctx: DetectDeclaredContext): ParityContractVerdict;
/**
 * The parse mode for a value-equality field's on-disk config file. Declared per
 * row in the CLI registry (`valueEqualityFieldsFor`) — derive-not-guess, so an
 * unrecognized format yields `unknown`, never a silent mis-parse.
 */
export type ValueEqualityFormat = 'yaml' | 'json';
/**
 * One value-equality field spec, resolved by the CLI registry from a contract id.
 * The EXPECTED value is deliberately NOT carried here — it is read from the
 * contract's own `expectedValueOrDerivation` (strategy#738 Q1: the manifest field
 * is the canonical, derived LOCALLY per Tenet 6). The registry supplies only WHERE
 * to look, never WHAT to expect (no second source of truth).
 */
export interface ValueEqualityField {
    /** Absolute path to the consumer config file (e.g. `<root>/.coderabbit.yaml`). */
    consumerPath: string;
    /**
     * The dotted config path as discrete SEGMENTS (`['reviews', 'profile']`), NOT a
     * pre-split string — a literal key containing a `.` would be mis-split otherwise
     * (totem-codex panel, strategy#738). The CLI registry owns the segments.
     */
    pathSegments: string[];
    /** Parse mode for {@link consumerPath}. */
    format: ValueEqualityFormat;
    /** Display name for the verdict line. */
    lineName: string;
}
/** Inputs + test seams for {@link detectValueEqualityContract}. */
export interface DetectValueEqualityContext {
    /** Current repo's cohort id for `consumers` applicability (verbatim parity with the other detectors). */
    repoId?: string;
    /** The field spec (file + path + format) the CLI registry resolved for this contract. */
    field: ValueEqualityField;
    /** Test seam — override the consumer file read. Production callers omit it. */
    readFile?: (absPath: string) => string | undefined;
}
/**
 * Detect drift for ONE `manifestation: value-equality` contract (strategy#738
 * Slice A, the Proposal 296 §13 promotion of the bot-review-config rows up from
 * `attestation`). Reads a scalar at a dotted path in the consumer's on-disk
 * config file and compares it — typed, never blanket-stringified — against the
 * row's own `expectedValueOrDerivation` (the canonical, read LOCALLY; NEVER
 * networks). Honors the verdict-state split + the honest-absent taxonomy the
 * cohort panel settled (strategy#738):
 *
 *   - `pass`    — the path resolves and the value equals the expected scalar.
 *   - `warn`    — present-but-mismatched, OR the path is absent on a present file
 *                 (incl. traversal through a non-object): applicable drift.
 *   - `unknown` — the file is present but unparseable: equality is unprovable
 *                 either way (value-equality is NOT a config-validity detector).
 *   - `skip`    — not-a-consumer / repo-id-unresolvable-under-scope / the file is
 *                 wholly absent (applicable-but-missing scaffold hedge, mirroring
 *                 detectVersionPinnedContract — flips to a drift `warn` once the
 *                 consumers lists are verified) / no expected declared.
 *
 * NEVER emits `fail` (the CLI edge owns `--strict` promotion). NEVER throws
 * (reads/parses degrade to skip/unknown). NEVER networks. Claim-class bound: a
 * `pass` asserts ONLY "this dotted path holds this scalar" — never that the bot
 * is on-demand, that the vendor loads it, or that the surface is enforced (those
 * are loaded/usable claims outside Slice A).
 */
export declare function detectValueEqualityContract(contract: ParityContract, ctx: DetectValueEqualityContext): ParityContractVerdict;
/**
 * §6 normalize-before-hash for a distributed lock artifact — byte-for-byte the
 * canonical `tools/build-strategy-doctrine.cjs` `normalize()` the publisher hashes
 * with (the builder header MANDATES the verifier reconcile with it): CRLF / lone-CR
 * → LF, strip trailing spaces/tabs per line, pop ALL trailing blank lines, join with
 * exactly one terminal `\n`. Idempotent — re-normalizing a shipped (already-normalized)
 * file is a no-op, so `hash(shipped)` holds cross-platform.
 *
 * DISTINCT from {@link normalizeManagedBlock} (which ALSO trims LEADING blank lines and
 * leaves NO terminal newline) — the two must not be conflated; this one mirrors the lock
 * publisher exactly. A golden test pins the byte-for-byte parity against a precomputed hash.
 */
export declare function normalizeLockArtifact(text: string): string;
/**
 * Full sha256 of a normalized lock artifact, `sha256:`-prefixed hex — byte-for-byte
 * the publisher's `sha256` helper (`'sha256:' + sha256hex(utf8)`). DISTINCT from
 * {@link hashManagedBlock} (a 12-char SHORT hash for managed-block verdict records);
 * the lock content-hash is the FULL digest the lock records.
 */
export declare function hashLockArtifact(normalized: string): string;
/** The single lock schema version this reader understands (mirrors the manifest gate). */
export declare const SUPPORTED_LOCK_SCHEMA_VERSION = 1;
/** One parsed `artifacts[]` entry from a strategy-doctrine lock (camelCase). */
export interface LockArtifact {
    /** Package-relative path to the distributed snapshot (resolves under the package dir). */
    path: string;
    /** `repo:path` strategy-canonical source for the vs-canonical layer. */
    canonicalSource: string;
    /** `sha256:`-prefixed hex of the normalized canonical content at publish. */
    contentHash: string;
    /** Strategy-canonical commit the snapshot was cut from (provenance-info only). */
    lastPublishedSha: string;
}
/** A parsed + validated strategy-doctrine lock (Proposal 292 §10.6). */
export interface StrategyDoctrineLock {
    schemaVersion: number;
    package: string;
    version: string;
    published: string;
    artifacts: LockArtifact[];
}
/**
 * Honest-absent lock parse outcome (discriminated union, mirroring
 * {@link parseParityManifest}):
 *   - `unparseable`        — invalid JSON or schema-validation failure.
 *   - `unsupported-schema` — `schema-version` ≠ the supported version.
 *   - `ok`                 — a fully parsed + validated lock.
 * NEVER throws — every failure is a first-class return value.
 */
export type LockParseResult = {
    status: 'unparseable';
    reason: string;
} | {
    status: 'unsupported-schema';
    schemaVersion: number;
} | {
    status: 'ok';
    lock: StrategyDoctrineLock;
};
/**
 * Parse raw `strategy-doctrine.lock` JSON into a validated {@link StrategyDoctrineLock}.
 * The `schema-version` gate runs BEFORE full validation so an incompatible future shape
 * is rejected with a clear `unsupported-schema` signal rather than a confusing
 * v1-shaped Zod failure (mirrors {@link parseParityManifest}). NEVER throws.
 */
export declare function parseStrategyDoctrineLock(jsonText: string): LockParseResult;
/** One verdict line from {@link detectLockContentContract} — per artifact × per layer. */
export interface LockContentLine {
    lineName: string;
    verdict: ParityContractVerdict;
}
/** Inputs + test seams for {@link detectLockContentContract}. */
export interface DetectLockContentContext {
    /** Current repo's cohort id for `consumers` applicability (verbatim parity with the other detectors). */
    repoId?: string;
    /**
     * The installed `@mmnto/strategy-doctrine` package dir (e.g.
     * `<gitRoot>/node_modules/@mmnto/strategy-doctrine`). The lock + each
     * `artifacts[].path` resolve under it; the CLI registry constructs it.
     */
    packageDir: string;
    /** Lock filename within {@link packageDir} (default `strategy-doctrine.lock`). */
    lockFileName?: string;
    /** Anchor for the vs-canonical sibling resolution (the git root). */
    gitRoot: string;
    /** Test seam — override file reads. Production callers omit it (reads UTF-8 on disk). */
    readFile?: (absPath: string) => string | undefined;
    /** Test seam — override the dir-exists probe. Production callers omit it. */
    dirExists?: (absPath: string) => boolean;
    /**
     * Test seam — override the real-path resolver for the symlink-escape guard (default
     * {@link defaultRealpath}). Returns the canonicalized absolute path, or undefined when
     * the target does not exist / is unresolvable.
     */
    realpath?: (absPath: string) => string | undefined;
    /** Test seam — override the strategy-root resolver (default {@link resolveStrategyRoot}). */
    resolveStrategyRootFn?: (cwd: string, options?: StrategyResolverOptions) => StrategyRootStatus;
    /** Test seam — local git-object existence check for the last-published-sha note. */
    gitObjectExists?: (sha: string, cwd: string) => boolean;
}
/**
 * Detect drift for the `manifestation: content-hash` strategy-doctrine lock-content
 * contract (mmnto-ai/totem#2107, strategy#754). Re-derives each distributed artifact's
 * `content-hash` from the consumed lock via the §6 normalize+sha256 contract and compares
 * it in TWO honest-absent layers, NEVER a fetch (Tenet 6/13):
 *
 *   - **self-consistency** (ALWAYS, local): `sha256(normalize(packaged file at path)) ==
 *     its lock content-hash` — proves the shipped snapshot is internally intact.
 *   - **vs-canonical** (ONLY when a local `../totem-strategy` sibling resolves): the same
 *     recompute against the artifact's lock `canonical-source` within the sibling — proves
 *     the pin still reflects strategy-canonical. SKIP honest-absent otherwise.
 *
 * Returns ONE line per artifact × per layer (the layers render SEPARATELY — a collapsed
 * "content drift" verdict would over-claim which layer drifted). `last-published-sha` is
 * provenance-INFO only (a LOCAL git-object existence note when a sibling resolves) — NEVER
 * a gating comparator, NEVER `sha == HEAD`.
 *
 * Top-level honest-absent: not-a-consumer / repo-id-unresolvable → skip; package not
 * installed → skip (the version-pin currency row senses the pin); lock absent while the
 * package is present → warn (structurally incomplete); lock unparseable / unsupported-schema
 * → warn.
 *
 * NEVER emits `fail` (the CLI edge owns `--strict` promotion). NEVER throws (reads
 * degrade). NEVER networks.
 */
export declare function detectLockContentContract(contract: ParityContract, ctx: DetectLockContentContext): LockContentLine[];
//# sourceMappingURL=parity-detect.d.ts.map