@career-evidence/core
v0.1.0
Published
Runtime-independent models and product policies for Career Evidence
Readme
@career-evidence/core
Runtime-independent Career Evidence models, schemas, constants, and pure product policies.
The default entrypoint is browser-safe. Reusable task-source HTTP providers have a
separate @career-evidence/core/providers entrypoint. Neither entrypoint reads files,
process environment, home directories, or CLI configuration.
import { TaskEvidenceSchema, deterministicAnalysis, buildTaskSummariesExport } from "@career-evidence/core";TaskSource is the runtime-independent task acquisition contract. It returns only
NormalizedTask[]. The shared providers accept configuration and runtime dependencies
explicitly; the CLI supplies local persistence. A task may carry an optional provider-neutral
identity with a source namespace, stable primary ID, public aliases, and exact URLs. The
human-facing taskId remains the display key, so older snapshots without identity stay readable.
import type { TaskSource, TaskSourceOptions, NormalizedTask } from "@career-evidence/core";
async function acquire(source: TaskSource): Promise<NormalizedTask[]> {
return source.getTasks({ cache: "prefer" });
}TaskSourceOptions.cache defaults to "prefer" (use a valid cache), supports
"refresh" (bypass the task snapshot TTL), and "only" (read the last valid local
snapshot, even if stale, with no network requests; reject if unavailable).
Implementations supply their configured task scope and own normalization,
deduplication, comments, and provider-specific retry/cache behavior.
Repository is independent of remote providers and describes a named URL with base
branches. ScmProvider supplies remote review evidence through prepareRepository
(metadata content fingerprint) and getPullRequests (matching normalized reviews,
match/truncation summary, plus an optional retryable failure). Queries may provide
task references, task dates, developer logins/emails, and choose metadata-only matching when
local Git already has complete implementation evidence. Each instance covers one collection run.
ScmOptions.force bypasses remote catalog/file/commit caches and restarts checkpoints.
Implementations own all transport, credentials, matching, caching, and run limits.
Local Git is separate and has no provider abstraction.
Persisted RepositoryEvidence.url is optional so CLI runtimes can represent local-only
checkouts without inventing a remote identity; historical evidence with a URL remains readable.
The normalized PullRequestEvidence model is reused for PRs/MRs: number is a
positive repository-local review number; body is its description; headBranch
and baseBranch are source and target branches. Optional fields carry creation/merge
time, author and configured-developer attribution, matched task IDs, score/reasons,
PR commits, local headHash/mergeCommitHash, and diff content. ScmRepositorySnapshot.reviews
optionally exposes acquired review metadata for repository-wide local commit membership.
Existing files remain readable because these additions are optional.
The model contains no GitHub DTOs or transport types.
SCM queries can provide developerScmIdentities for provider-scoped usernames or stable account IDs, alongside the compatible developerGithubLogins and developerGitEmails fields. Normalized PR/MR evidence can optionally record diffTruncated; absent fields preserve existing evidence parsing and fingerprints. Provider authentication, HTTP clients, caches, and filesystem behavior remain in the CLI.
textMatchesTaskId performs complete-token, case-insensitive task matching, avoiding
prefix collisions such as ABC-1 with ABC-10. taskMatchingIds applies the explicit
exact, include-parent, or aggregate-children hierarchy policy without implicitly
expanding task relationships.
taskCorrelationTarget exposes only references that a source knows: the public task key,
provider aliases, and exact task URLs. namespace plus primaryId identifies the source object
without treating an internal UUID or the numeric part of a key as a public alias. Therefore
PAY-123, 123, and #123 are not automatically equivalent. Jira uses site/cloud scope and
its immutable issue ID; Linear uses organization and issue UUID; ClickUp retains workspace,
native ID, custom ID, CU-..., #..., and its task URL when available.
Correlation utilities turn those bounded references into provider-neutral evidence.
correlateText records the source field, exact matched reference, source identity, direct or
inherited derivation, rule, relation, and per-signal decision; resolveArtifactCorrelation produces a matched, candidate,
or excluded artifact result and preserves conflicts. correlationSupportsImplementation
keeps references, dependencies, ignores, and reverts from becoming implementation proof.
An alias shared by multiple namespaces is retained as an ambiguous candidate. PR-linked commits
use via-pull-request, while their own subject/body references remain direct signals.
correlateTitleSimilarity normalizes separators, camel case, common action prefixes, and light
English word forms, then records a deterministic rank and matched terms. Its results are always
review candidates, never probability claims or automatic implementation matches. A persisted
manual confirmation or exclusion is represented by an explicit manual signal and takes
precedence over automatic signals. Override schemas bind that decision to repository, artifact
identity, and an exact branch/commit/PR revision so it cannot silently move with mutable Git data.
The functions are deterministic and perform no Git, network, cache, or persistence work.
correlateText(input, targets, scope?) also recognizes structured references absent from the
catalog. Optional TaskReferenceScope supplies the tracker provider and namespace, including
when no targets were loaded. Unknown references retain unresolved: true and cannot support
implementation or trigger title-based reassignment. Native ClickUp IDs can resolve to a known
task's custom public ID. Tracker URLs and bounded provider keys are supported; ordinary words,
bare numbers and hexadecimal hashes are not inferred as unknown IDs. Explicit unresolved
dependencies/references preserve their relation without invalidating a known implementation;
unknown implementation ownership and contradictory branch/PR identities remain conflicts.
Runtimes can store optional RepositoryEvidence.unresolvedReferences diagnostics independently
of a selected task's artifact links.
correlateContextualSimilarity({ texts, code }, targets) compares branch/commit/PR names,
local changed paths and diff identifiers with every known task's title and description.
LocalCodeContext contains a local range/commit source, paths and identifiers, never a patch.
contextualTerms splits separators, camelCase, PascalCase/acronyms, snake_case and kebab-case,
applies light English stemming, and removes numeric/hash noise, common action words, code
keywords, workspace tags such as [Core/CLI], and generic terms such as cli, match,
media, modified, payment, method, service and update.
isContextualPath extends the existing relevant-path policy to exclude generated, lock,
minified and known binary paths; the runtime must also reject Git-detected binary content.
Contextual signals use title-similarity, description-similarity, changed-path-similarity
and diff-context-similarity. Each retains task identity, source field, matched terms, local
source, rank, matching title/description terms, up to five matching paths, and an additive
breakdown. The rank is the sum of four rounded contributions:
- Title: up to 30 points, proportional to matched normalized title terms.
- Description: 10 points per distinct matched description term, capped at 20.
- Paths: 15 points per distinct matching path term, capped at 30.
- Diff identifiers: 10 points per distinct matching identifier term, capped at 20.
Repeated occurrences do not add points. At least two terms, or one term of five or more
characters, must match; rank must reach 20. Only tasks within 25 points of the best rank
remain candidates. If multiple source identities are within 10 points of the best, those
results are ambiguous. These constants are exported as CONTEXTUAL_CORRELATION_POLICY.
Rank orders suggestions; it is neither a probability nor evidence of implementation.
Every contextual signal remains candidate, even at 100, until explicit confirmation.
Exact references and manual decisions retain priority. Confirmed ancestors pass their
effective manual decision to branch/PR commits without inheriting superseded ambiguity.
All contextual schema fields are optional, so historical evidence still parses unchanged.
Core performs no extraction, filesystem access, Git execution, network requests, embeddings,
or LLM calls; runtimes own extraction limits and privacy.
applyCorrelationRanking(correlation, policy, aiDecisions?, autoMatchIdentities?) applies a configurable
buildIn or ai relevance rank to purely lexical candidates. CorrelationRankingPolicySchema
validates minRank as an integer from 0 to 100; scores below the threshold become excluded audit signals.
Exact references, inherited ownership, unresolved references and manual decisions are unchanged.
Optional per-signal ranking metadata records the strategy, rank, threshold, assessment and reason,
while original contextual score breakdowns remain intact. AI policy defaults to decisionMode: "review",
which leaves supported links as candidates. With decisionMode: "auto", a supported identity at or above
minRank becomes matched implementation evidence; callers can scope automatic matches to the identities
selected by the current task evidence. uncertain results at or above minRank and unavailable AI results remain
candidates, while unrelated and ranked below-threshold results are excluded. Ambiguity is recalculated among
surviving identities.
AiCorrelationRankingResponseSchema defines
bounded structured decisions; runtimes must also validate complete, unique membership in the
supplied candidate set. Core neither constructs an AI provider nor reads patches or writes caches.
CORRELATION_RANKING_POLICY_VERSION is currently 2; runtimes include it in ranking collection and
stage-cache identities so prompt or merge-policy changes cannot silently reuse older decisions.
AnalysisProvider supplies one structured generation through
generateStructured({ instructions, input, outputSchema, maxOutputTokens, onUsage }),
returning untrusted parsed JSON. maxOutputTokens is provider-neutral; adapters map
it to a supported wire parameter. onUsage reports provider accounting and is not
an input estimate. The provider knows nothing about task sources, SCM providers, repositories,
credentials, model names, or HTTP. Callers supply Core's conservative instructions
and AnalysisOutputJsonSchema, then validate every result with
GeneratedAnalysisSummarySchema. Generated string and array sizes are bounded in
the schema, and normalizeGeneratedAnalysisSummaryInput safely trims otherwise
well-typed overlong model fields before validation. Areas and evidence references are derived
deterministically and combined into AnalysisSummarySchema without asking the model
to reproduce them. Schema hints do not imply native schema enforcement.
Providers choose their own structured-output mechanism and expose safe
AnalysisProviderError categories rather than raw transport errors.
ANALYSIS_PROMPT_POLICY_VERSION and
GENERATED_ANALYSIS_SUMMARY_SCHEMA_VERSION identify the prompt semantics and
intermediate response contract for runtime cache identities; they do not add
filesystem or cache behavior to Core.
Core retains result semantics, allowed signals, fallback/defer policies, evidence
references, and cache decisions. The CLI orchestrates prepared/redacted evidence,
chunks, consolidation, persistence, and lazy runtime provider composition. Its
OpenAI-compatible adapter supplies transport for several named services, local
runtimes, and custom endpoints; a native adapter can be added without duplicating
this workflow. Analysis generator identifiers are nonempty strings so provider
types and the deterministic fallback can be persisted without coupling Core to
the CLI's provider list.
Shared task sources
import { TaskSourceConfigSchema } from "@career-evidence/core";
import { createTaskSource } from "@career-evidence/core/providers";
const config = TaskSourceConfigSchema.parse({
provider: "linear",
apiKey: "<personal-api-key>",
teamIds: ["11111111-1111-4111-8111-111111111111"],
});
const source = createTaskSource(config, {
fetch: globalThis.fetch,
logger: { info() {}, warn() {}, error() {} },
// Optional cache: { read(key): Promise<unknown>, write(key, value): Promise<void> }
});
const tasks = await source.getTasks();ClickUpTaskSource, LinearTaskSource, JiraTaskSource, TaskSourceRuntime,
TaskSnapshotCache, TaskSourceError, and adfToMarkdown are exported from
@career-evidence/core/providers. Factory dispatch exists only in
src/factories/task-source.ts. The main entrypoint exports browser-safe provider
config schemas and types, without importing the providers.
Runtime may inject fetch, an atomic snapshot cache, now, sleep, and
bindContext (an optional hook for protecting persisted evidence from a source
change). logger is required. An optional fetchJson preserves the CLI's existing
ClickUp transport; new adapters always use the bounded shared transport with the
injected fetch. Without a cache, providers acquire data on each call and reject
cache: "only".
Linear/Jira verify the authenticated organization/account before online cache
reuse. Offline reads validate the configured scope and use the last authenticated
snapshot; they cannot verify current credentials or server permissions. Hosts,
scopes, filters, and authenticated account identities isolate snapshots; API keys
and Basic authorization values never enter identities. No token-derived hashes
are persisted. New providers reject incomplete results instead of returning a
partial array or overwriting the last complete snapshot. A consumer can inspect
TaskSourceError.code for HTTP/GraphQL failures; diagnostics omit remote bodies.
The TaskSource contract has no cancellation signal, so no second cancellation
contract was introduced.
See the CLI documentation for full configuration, permissions, and limits.
