/** * Codebase style fingerprint (change: add-codebase-style-fingerprint). * * A deterministic, DESCRIPTIVE per-language idiom profile, tallied during the existing * AST walk (see `extractTSGraph`/`extractPyGraph`/`extractGoGraph` in `call-graph.ts`) — no * second parse, no new parsing dependency. For each supported language the analyzer counts a * fixed, closed set of mutually-exclusive syntactic choices the code actually makes (arrow vs. * declared function, `const` vs. `let`, ternary vs. `if`, `await` vs. `.then`, template vs. * concatenation, function-naming case) and rolls them up to the repository, each * community/region, and (on request) a single file. * * Three honesty rules are load-bearing (mirrors the IaC extractors and the confidence-boundary * invariant): * 1. Counters are reported as **ratios with their sample sizes**, never bare percentages. * 2. A counter below a FIXED evidence floor reports a null signal (`below_floor`) — never a * default value or a misleading extreme. * 3. A choice the language/compiler/formatter makes for the author (e.g. Go ties identifier * case to visibility / gofmt canonicalizes) reports a null signal (`enforced`) rather than * a tautological `1.0`. Which scopes are enforced is DECLARED per language here, never * inferred at runtime. * * Descriptive, not prescriptive: this measures what the code IS. It emits no lint diagnostic, no * quality judgment, and NO composite "style score" — a blended number would be the hidden tuning * constant the north star exists to exclude (decision c6d1ad07). Ranking and conformance are the * agent's; OpenLore supplies the measured distribution and the evidence behind it. * * The counter set per language is DATA (`STYLE_LANG_SPECS`), so a language with no declared set * contributes nothing (fail-soft), exactly like the CFG overlay's unsupported-language behavior, * and the set tracks the language-support registry as languages land. * * Deterministic: integer tallies over a deterministic walk, sorted keys, no clock — byte-identical * across re-analyses of a fixed repository state. */ /** Bump when the persisted artifact shape changes incompatibly. */ export declare const STYLE_SCHEMA_VERSION = 1; /** * Fixed evidence floor: a counter with fewer than this many observations reports a null signal. * A constant on purpose — NOT a caller-tunable knob (a tunable floor would be a hidden parameter * the honesty contract bans). 12 is enough to distinguish a real majority from coin-flip noise. */ export declare const STYLE_EVIDENCE_FLOOR = 12; /** The closed set of idiom counters, in deterministic order. */ export declare const IDIOM_KEYS: readonly ["functionForm", "binding", "conditionalForm", "asyncForm", "stringForm", "functionNaming"]; export type IdiomKey = (typeof IDIOM_KEYS)[number]; /** Why a counter withheld its ratio. */ export type NullReason = 'below_floor' | 'enforced'; /** A measured idiom (with evidence) or an honestly-withheld null signal. */ export type IdiomSignal = { dominant: string; ratio: number; samples: number; options: Record; } | { signal: null; reason: NullReason; }; /** Raw integer tallies for one idiom: option name -> count. */ export type RawIdiomTally = Record; /** Raw counters for one file (single-language, since extraction dispatches per file language). */ export interface FileStyleRaw { filePath: string; language: string; /** Only the idioms this language's spec declares are present. */ counters: Partial>; /** Number of function definitions observed in the file (evidence weight). */ functionsSampled: number; } /** A rolled-up, honesty-filtered profile for one language at one granularity. */ export interface LanguageProfile { language: string; idioms: Partial>; functionsSampled: number; } /** A community/region profile (the same communities the map computes). */ export interface RegionProfile { communityId: string; label?: string; byLanguage: LanguageProfile[]; } /** The persisted style-fingerprint artifact. */ export interface StyleFingerprint { schemaVersion: number; evidenceFloor: number; /** Repository-level profile, sliced per language. */ byLanguage: LanguageProfile[]; /** Per community/region profile. */ regions: RegionProfile[]; /** Raw per-file counters, retained for on-demand single-file profiles + incremental updates. */ files: FileStyleRaw[]; /** file path -> the community id it is attributed to (plurality of its functions). */ fileRegions: Record; /** Languages that produced a fingerprint (sorted). */ generatedLanguages: string[]; } /** One language's declarative idiom set + the scopes its toolchain enforces (→ null signal). */ export interface StyleLangSpec { language: string; idioms: IdiomKey[]; /** Idioms the language/compiler/formatter decides for the author → reported as `enforced` null. */ enforced: IdiomKey[]; } /** * The per-language counter sets — DATA, not control flow. A language absent here contributes no * fingerprint (fail-soft). Conservative by design: an idiom is listed only where it is a genuine, * soundly-measurable discretionary choice in that language. */ export declare const STYLE_LANG_SPECS: Record; /** Languages for which a style fingerprint is computed — the registry derives the capability from this. */ export declare const STYLE_FINGERPRINT_LANGUAGES: ReadonlySet; /** * Classify a name's case ONLY when it expresses a multi-word convention (a case boundary: an * interior uppercase or an interior underscore). Honesty rules baked in so a name can't be * mis-bucketed and skew the house-style ratio: * - A leading/trailing underscore RUN is stripped first — a privacy prefix (`_helper`) or a * dunder (`__init__`) is not a naming-CASE choice, so it must not drive the verdict (a bare * `_` then classifies as null, not snake_case). * - A name mixing an interior underscore AND an uppercase letter (`mixed_Case`) follows neither * convention cleanly → null, rather than being forced into snake_case. * - A single all-lowercase word (`handle`) or SCREAMING_CASE (`MAX_RETRIES`) exercises no * camel-vs-snake discretion → null (excluded from the ratio, not a thumb on the scale). */ export declare function classifyNamingCase(name: string): 'camelCase' | 'PascalCase' | 'snake_case' | null; /** * Minimal structural view of a tree-sitter node (avoids a hard tree-sitter type import). The * index accessors (`namedChildCount`/`namedChild`) are optional: the real tree-sitter `SyntaxNode` * provides them and the walk prefers them because they DON'T allocate a fresh child array per node * (the `.namedChildren` getter does, which dominated the tally cost); a plain test object that only * supplies `namedChildren` still works via the fallback. */ export interface StyleAstNode { type: string; text: string; children: StyleAstNode[]; namedChildren: StyleAstNode[]; namedChildCount?: number; namedChild?(i: number): StyleAstNode | null; } /** * Tally idiom counters for one file by walking its already-parsed tree once. Pure and * deterministic. `functionNames` are the names the call-graph extractor already collected for the * file (reused for naming-case, no re-derivation). A language with no spec returns null. */ export declare function tallyFileStyle(params: { language: string; rootNode: StyleAstNode; functionNames: string[]; }): FileStyleRaw | null; /** Roll a set of single-language files up to a {@link LanguageProfile}. */ export declare function rollupLanguage(files: FileStyleRaw[], language?: string, floor?: number): LanguageProfile; /** A node carrying its file + community attribution (subset of the call-graph FunctionNode). */ export interface StyleNodeRef { filePath: string; communityId?: string; communityLabel?: string; } /** * Attribute each file to ONE community: the community holding the plurality of its functions * (ties broken by lexicographically smallest community id — deterministic). A file with no * community-bearing function is left unattributed. */ export declare function attributeFilesToRegions(nodes: StyleNodeRef[]): { fileRegions: Record; labels: Record; }; /** * Assemble a {@link StyleFingerprint} from raw per-file counters and a GIVEN file→region map + * labels. Pure + deterministic (every collection sorted by a stable key). Used both by the full * build (after attributing files to regions from the call graph) and by the incremental watcher * update (which reuses the stored `fileRegions` rather than recomputing communities). */ export declare function assembleFromRegions(rawFiles: FileStyleRaw[], fileRegions: Record, labels: Record, floor?: number): StyleFingerprint; /** * Assemble the full {@link StyleFingerprint} from raw per-file counters and the call-graph nodes * (which carry community membership, for region attribution). Pure + deterministic. */ export declare function buildStyleFingerprint(rawFiles: FileStyleRaw[], nodes: StyleNodeRef[], floor?: number): StyleFingerprint; /** Roll a SINGLE file's raw counters up to a per-file profile (floor still applies — honest). */ export declare function fileProfile(raw: FileStyleRaw, floor?: number): LanguageProfile; /** * Compact top-idioms summary for `orient`: the strongest few measured idioms for a language * profile, above the floor and not enforced, as short `key=dominant (ratio)` strings. Bounded. */ export declare function compactIdiomSummary(profile: LanguageProfile, limit?: number): string[]; //# sourceMappingURL=style-fingerprint.d.ts.map