7 minutes read

Decision records

These records explain the choices behind Offing's architecture, data format, contracts, and policy. Each one is accepted unless a later record supersedes it, or unless its status says otherwise. Records are numbered in the order they were written; this page groups them by theme.

Detectors

# Title Decision
0002 Add Go as a first-class detector ecosystem Add evidence-backed Go runtime, toolchain, and direct-module lifecycle detection through the existing detector SDK, without requiring the Go toolchain or network access at scan time.
0007 Detect end-of-life container base images from Dockerfiles and Compose files Add a container detector that reports base-image references whose release line has a vendor-published end of life.
0008 Detect removed and deprecated Kubernetes APIs in manifests, Helm charts, and kustomizations Add a kubernetes detector that reports apiVersion/kind pairs the Kubernetes project has documented as deprecated or no longer served.
0009 Detect end-of-support JDK releases and relocated Maven dependencies in JVM projects Add a java detector for pinned or targeted JDKs and Maven coordinates that a vendor or maintainer has documented as out of support or moved.
0011 Detect unsupported Rust toolchains and abandoned or yanked crates Add a rust detector that reads Cargo and toolchain files and reports lifecycle risks an authoritative source states.
0012 Detect unsupported .NET targets and deprecated NuGet packages Add a dotnet detector for unsupported .NET SDK/runtime lines and deprecated NuGet packages with publisher evidence.
0013 Detector maturity levels and the evidence to move between them Use three levels — experimental, beta, and stable — with fixed evidence floors (fixtures, corpus size, precision, recall) to move between them.
0014 Detect retired CI runner images Add a ci-images detector that reports only image lifecycle risks the platform's authoritative documentation explicitly states.
0015 Corpus fetch strategy: sparse checkout, concurrency 16 Default the public-repository corpus to sparse checkout at concurrency 16, with cache invalidation keyed to detector input declarations.

Data and contracts

# Title Decision
0004 Key lifecycle rules by PURL and VERS with provenance Move every ecosystem to one offing.registry.v2 format keyed by Package URL and VERS, with provenance on each rule.
0005 Draft lifecycle rules with importers; never write the registry Let importers draft rules from one authoritative source; a person reviews every draft and changes registry/ in a pull request.
0006 Ship lifecycle data as a versioned, content-addressed bundle Publish and consume lifecycle data as an offing.data-bundle.v1 document separate from the code release.
0010 Record announced end-of-life dates that have not happened yet Add a scheduled-end-of-life event for announced future ends, reported at low severity and promoted by a reviewed change after the date.
0016 CLI exit codes and error codes Map failures to five fixed classes and exit codes: policy 1, usage 2, data 3, parse 4, internal 5.
0017 Do not read OpenEoX documents yet; keep CLE as the interchange target Scans never read OpenEoX; do not ingest it until the Core Schema is final, and keep CLE as the standards interchange path.
0020 License the lifecycle dataset under CC BY 4.0 License registry/ and first-party schemas in the data-only package under CC BY 4.0; keep the rest of the repository Apache-2.0.
0022 Match Python TestCase method calls with a method shape Add a Python-only method symbol shape that matches a call by name on any receiver inside a class that directly subclasses unittest.TestCase or an alias of it.
0028 Publish a self-contained MCP output schema Inline every cross-file $ref before the MCP server advertises a tool's schema and throw when one cannot resolve; same-document references stay, and sibling keywords win over the inlined target.
0032 Split the MCP server into one file per tool Give each MCP tool its own file under src/mcp/tools/, list them in a small registry, and prove with a tools/list snapshot that no advertised name, description, input schema, output schema, or annotation changed.
0033 Require the retrieval date on every lifecycle source Make sources[].accessedAt required in registry v2, backfill every bundled record, and let the importer runner stamp the run date so every finding shows when its source was read.
0037 Recommend a release line from bundled data only Add recommend_version and offing recommend: the newest unended line whose end date is at least 180 days away, from bundled rules only; no-data is explicit and never says "latest".
0036 Add Deno and Elixir to the public validation schema Add deno and elixir to the published corpus ecosystem enum when those detectors gain a public corpus. The change is additive.
0034 Publish the detector limits in the SDK Export DETECTOR_LIMITS and its DetectorLimits type so the file-size, depth, and vendored-directory bounds are part of the typed detector contract and conformance reads them from there.

Adoption

# Title Decision
0018 Ship v0.8.0 (adoption) and v0.9.0 (visibility) before v1 Ship adoption then visibility before v1, with usage before attention, and record post-v1 ideas as unscheduled epics.
0019 Privacy-first adoption metrics; opt-in telemetry only after v1 Keep product telemetry off by default forever as the default; any opt-in comes only after a separate post-v1 decision.
0021 Ship adoption and visibility as one release, with one launch Merge v0.9.0 into v0.8.0 and replace the three mini-launches with one launch that follows the release.

Quality

# Title Decision
0023 Define reference quality as measurable, enforced criteria Proposed. Define eight quality criteria, each enforced by a failing check; zero new debt; existing debt allowlisted with an owner and an expiry of 2027-01-26.
0025 Choose the linter and formatter Lint with ESLint and typescript-eslint (type-aware); format with Biome; do not use Biome for typed lint or Prettier for format.
0026 Document the public API and enforce it with lint Put a behavior-focused doc comment on every public declaration and enforce it with a local ESLint rule; no contract semantics change.
0027 Keep fixtures out of scanners' sight with neutral names Commit manifest-shaped fixtures under a .fixture suffix and restore the real name in a temporary directory at test time; reject archives and dismissals; scanner config is a narrow fallback.
0029 Cut scanner complexity by extracting the line masker and replacing branch chains with tables Move the per-language literal scanner to src/usage/masking.ts, dispatch readers on tables, and prove parity differentially against a build of main; the SDK export surface is unchanged.
0030 Select corpus repositories independently of results; target 200 per ecosystem Freeze eligibility and stack variety for all 23 buckets before scanning; retain poor results and publish honest shortfalls against 200 reviewed repositories per bucket. Accepted on maintainer merge of the PR for #2116.

Operations

# Title Decision
0024 CI lanes: pull request, merge queue, main, nightly, release Proposed. Five CI lanes with wall-clock budgets; one required check (ci-ok); the merge queue is the proof that lands on main.

Policy

# Title Decision
0001 TypeScript-first, local-first architecture Build v0.1 in TypeScript on Node.js 22 or newer, sharing one language across CLI, engine, detectors, Action, and MCP, with no hosted backend.
0003 Generate host plugins from shared Offing assets Keep Skill, runtime, rules, and migration behavior as canonical shared sources and generate Codex and Claude plugins from them so CI fails on drift.
0031 Layered architecture and the allowed-imports table Proposed. Seven layers (domain, SDK, core, detectors, services, reporters, adapters) with one allowed-imports table and runtime-access rules; each epic #1990 follow-up adds its rule to the checker.
0035 One error model with stable reason codes Every failure carries one reason code that fixes its class and exit code; the CLI error document gains error.reason and MCP failures carry the code in _meta.offing.
View Markdown

Use with an agent
View Markdown

Open in