Skip to content

fix(core,evaluator): qualified relatesTo/conflictsWith are inert in lint; cross-repo supersession is an error everywhere (#299) - #307

Merged
mbeacom merged 2 commits into
mainfrom
fix/lint-qualified-refs
Oct 10, 2026
Merged

mbeacom merged 2 commits into
mainfrom
fix/lint-qualified-refs

Conversation

@mbeacom

@mbeacom mbeacom commented Oct 10, 2026

Copy link
Copy Markdown
Owner

Closes #299.

What and why

The schema accepts <log>:<id> references, but the surfaces disagreed about them:

  • adr lint failed a qualified relatesTo with exit 1.
  • The evaluator, the marker resolver, and MCP treated the same reference as inert.
  • In the opposite direction, the evaluator treated a qualified supersedes as inert (or passing, given a snapshot), while lint failed it.

This PR implements the accepted ADR-0059:

  • Clause 5. Lint reports a log-qualified relatesTo or conflictsWith as federated-ref-unresolved at info instead of dangling-relatesTo (error) or dangling-conflictsWith (warn). This is the amendment to ADR-0031 clause 5 that ADR-0059 declares, and only the relatesTo case lowers an exit code. Measured on a fixture, adr lint and adr explain go from 1 to 0, while check and queue were already 0. A qualified reference never resolves to a local record that shares its bare id.
  • Clause 4. Cross-repository supersedes/supersededBy is a dangling-* error everywhere.
    • Lint already failed it, and its message now says why.
    • adr evaluate now fails it as no-orphan-refs.dangling-supersedes, even when a snapshot lists the id.
    • A reference qualified with the evaluator's own resolution log still counts as local.
  • Not changed: unqualified references, and the evaluator's handling of qualified relatesTo, which now agrees with lint.

Checklist

  • DCO signed off.
  • Recorded decision: ADR-0059 clauses 4–5 (accepted). Action item 2 is ticked, verified in the tree.
  • Schema changed: n/a.
  • @adrkit/core changed, so packages/ci/dist is regenerated under linux/amd64 Bun 1.4.2. The bundles gain parseAdrRef and this change, and nothing else.
  • New tests were observed failing first (ADR-0016). That's 6 in core, 4 CLI fixture tests, and 4 in the evaluator, plus a mutation check on the bare-id rule.
  • Full bun test: 4345 pass. typecheck, lint, check:deps, check:stale-refs, check:changelog, and adr lint (59 records, clean) also pass.

Notes for reviewers

  • The CHANGELOG entry is marked as a behavior change.
  • docs/RELEASING.md names the amendment in its SemVer paragraph.
  • specs/005-…/contracts/pass-0-evaluation.md still describes the old evaluator behavior. I left it alone because specs/ records history.

Copilot AI balanced review requested due to automatic review settings October 10, 2026 21:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Same-log-qualified supersededBy references remain incorrectly dangling in the evaluator.

1 open finding
What changed in this PR

Aligns lint and evaluator handling of qualified ADR references under ADR-0059.

Changes:

  • Reports qualified relatesTo/conflictsWith as informational.
  • Rejects cross-log supersession in the evaluator.
  • Updates tests, documentation, and Action bundles.

Repository ADR MCP context was unavailable, so marker-aware decision compliance could not be verified.

File Description
CHANGELOG.md Documents behavior changes.
docs/​RELEASING.md Records amended compatibility policy.
docs/​adr/​0059-aggregate-decision-corpora-across-an-organization-s-repositories-as-a-pinned-rea.md Marks implementation action complete.
packages/​core/​src/​validate/​corpus-invariants.ts Classifies qualified references.
packages/​core/​test/​corpus-invariants.test.ts Tests core classifications.
packages/​cli/​test/​lint.test.ts Tests lint output and exits.
packages/​evaluator/​src/​rules/​no-orphan-refs.ts Rejects cross-log supersession.
packages/​evaluator/​src/​rules/​supersession-consistent.ts Improves qualified successor diagnostics.
packages/​evaluator/​test/​no-orphan-refs.test.ts Tests supersession handling.
packages/​evaluator/​test/​supersession-consistent.test.ts Tests qualified supersededBy.
packages/​ci/​dist/​index.js Regenerates governing Action bundle.
packages/​ci/​dist/​queue-action.js Regenerates queue Action bundle.
packages/​ci/​dist/​portal-action.js Regenerates portal Action bundle.

🧠 Review effort: Balanced

Comment thread packages/evaluator/src/rules/supersession-consistent.ts Outdated
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Decisions governing this change

11 accepted decisions govern this change · 1 historical record

Show all 11 governing decisions and why each applies
  • 0001 — Record architecture decisions as versioned markdown in git
    • via path: docs/adr/**
  • 0003 — Ship as a Spec Kit extension plus a standalone CLI, not a competing harness
    • via path: packages/cli/**
  • 0016 — Require every check to be observed failing before it counts as coverage
    • via path: packages/*/test/**
    • via path: packages/core/src/validate/**
  • 0027 — Ratify the deterministic evaluator and bind calibration reporting to the first probabilistic pass
    • via path: packages/evaluator/**
  • 0030 — Keep extension surfaces that carry a dependency tree outside this repository
    • via path: packages/ci/**
  • 0031 — Publish a narrow consumer SDK as the contract, and document the CLI JSON as its sibling
    • via path: docs/RELEASING.md
  • 0032 — Publish one lockstep OCI image after the coordinated release succeeds
    • via path: docs/RELEASING.md
  • 0035 — Execute the gates that certify a pull request from the default branch
    • via path: packages/ci/**
  • 0036 — Expose the governing-decisions Action through one root Marketplace entry point
    • via path: docs/RELEASING.md
    • via path: packages/ci/dist/index.js
  • 0041 — Regenerate committed artifacts on Dependabot pull requests with default-branch scripts behind a maintainer label
    • via path: packages/ci/dist/**
  • 0059 — Aggregate decision corpora across an organization's repositories as a pinned, read-only federation
    • via path: packages/core/src/validate/corpus-invariants.ts
Historical records that once covered this change (1)

These no longer bind this change, and are listed for context only:

  • 0005 — Gate proposals with a deterministic-first evaluator and declarative escalation (superseded) — superseded by 0027
    • via path: packages/evaluator/**

Links point at 28ed61d, this run's GITHUB_SHA. Run adr explain <path> locally to see why a file is governed.

@mbeacom mbeacom self-assigned this Oct 10, 2026
@mbeacom mbeacom added bug Something isn't working gate-change-acknowledged A maintainer has seen and accepted this PR's change to the CI gate surface (ADR-0035) labels Oct 10, 2026
@mbeacom
mbeacom force-pushed the fix/lint-qualified-refs branch from 69166fc to a103faf Compare October 10, 2026 22:16
@github-actions github-actions Bot removed the gate-change-acknowledged A maintainer has seen and accepted this PR's change to the CI gate surface (ADR-0035) label Oct 10, 2026
@mbeacom mbeacom added the gate-change-acknowledged A maintainer has seen and accepted this PR's change to the CI gate surface (ADR-0035) label Oct 10, 2026
…nert in lint, and cross-repository supersession as an error everywhere (#299)

The schema accepts `<log>:<id>` references, but `adr lint` failed a
qualified `relatesTo` as `dangling-relatesTo` (error) while the
evaluator, the marker resolver, and MCP all treated it as inert. Under
ADR-0059 clause 5 (which amends ADR-0031 clause 5 for this case), lint
now reports a qualified `relatesTo` or `conflictsWith` as
`federated-ref-unresolved` at `info`. Only the `relatesTo` case lowers
an exit code; a dangling `conflictsWith` was already `warn`. A qualified
reference never resolves to a local record with the same bare id.

ADR-0059 clause 4 keeps cross-repository supersession a dangling-* error
everywhere. Lint already failed it and now says why. `adr evaluate`
treated a qualified `supersedes` as inert (or passing, with a snapshot)
and now fails it as `no-orphan-refs.dangling-supersedes`, naming the
clause; a reference qualified with the evaluator's own resolution log
still counts as local.

packages/ci/dist is rebuilt under linux/amd64 Bun 1.4.2 for the core
change. Every new test was observed failing first (ADR-0016). ADR-0059
action item 2 is ticked.

Signed-off-by: Mark Beacom <m@beacom.dev>
… every check

Copilot found that a supersededBy qualified with the evaluator's own resolution log (here:0002 under resolutionLog here) was still dangling: supersession-consistent compared the raw ref against bare ids before the cross-log test mattered, and the reciprocity, pair, and cycle checks compared raw refs too. Refs qualified with the resolution log are now normalized to their bare id once, up front, so every check agrees with no-orphan-refs; a ref naming another log (or any qualified ref with no resolution log) stays raw and keeps the ADR-0059 clause 4 failure. Four new tests failed before the fix (ADR-0016).

Signed-off-by: Mark Beacom <m@beacom.dev>
@mbeacom
mbeacom force-pushed the fix/lint-qualified-refs branch from a103faf to 36eff01 Compare October 10, 2026 22:33
@github-actions github-actions Bot removed the gate-change-acknowledged A maintainer has seen and accepted this PR's change to the CI gate surface (ADR-0035) label Oct 10, 2026
@mbeacom mbeacom added the gate-change-acknowledged A maintainer has seen and accepted this PR's change to the CI gate surface (ADR-0035) label Oct 10, 2026
@mbeacom
mbeacom merged commit 6f4de5c into main Oct 10, 2026
22 of 23 checks passed
@mbeacom
mbeacom deleted the fix/lint-qualified-refs branch October 10, 2026 23:24
mbeacom added a commit that referenced this pull request Oct 10, 2026
…est the portal bundle's datetime as-of

packages/ci/dist rebuilt under linux/amd64 Bun 1.4.2 on top of main (after #307, #308, #314). The portal bundle now takes the SDK's --as-of grammar: a new bundle test resolves 2026-01-08T23:30:00-05:00 to 2026-01-09, and the usage-error test uses a timezone-less datetime with core's message. Both failed against main's bundle (ADR-0016).

Signed-off-by: Mark Beacom <m@beacom.dev>
mbeacom added a commit that referenced this pull request Oct 10, 2026
…ut publishing it (#295) (#312)

* feat(core,cli,sdk): close the SDK's remaining publication gates without publishing it (#295)

- ADR-0031 item 8 / ADR-0053 item 3: core exports todayUtcDate, the
  absent-input `--as-of` default, and replaces every inline copy: adr
  queue, the queue Action (bundle regenerated), adr new's scaffold, and
  the SDK's queue(). The portal now takes the SDK's echoed default
  (queue().asOf) instead of computing its own. Tests ban the inline
  expression in all of them.
- ADR-0031 item 4 / ADR-0053 item 8: `adr explain`, `adr lint`, and
  `adr new --json` now come from core formatters (packages/core/src/
  report). Old and new CLIs produced byte-identical stdout and exit codes
  on 53 command lines over this corpus and the SDK fixtures; committed
  goldens hold it.
- ADR-0031 item 6 / ADR-0053 item 5: a conformance fixture under
  packages/core/test/conformance/golden: the CLI must reproduce its
  queue and check goldens byte for byte, and the SDK must agree with them.
- ADR-0031 item 5: docs/RELEASING.md documents the SDK and CLI JSON
  consumer contracts.

Nothing is published: RELEASE_PACKAGES, exports, files, and the
no-release assertions are untouched. packages/ci/dist rebuilt under
linux/amd64 Bun 1.4.2. Every new test was observed failing first
(ADR-0016). Ticked: ADR-0031 items 4, 5, 6, 8 and ADR-0053 items 3, 5, 8.

Signed-off-by: Mark Beacom <m@beacom.dev>

* fix(sdk,portal): accept the CLI's --as-of grammar in queue(), so the portal takes ISO datetimes

Review on #312 found three gaps:
- #295 promised the portal would accept ISO datetimes once the default
  moved to core, but it still refused them. The SDK's queue({ asOf }) now
  resolves a supplied value through core's resolveAsOf, the grammar
  `adr queue --as-of` uses (a bare date, or an ISO datetime with an
  explicit zone), and echoes the resolved UTC date in QueueView.asOf;
  anything else throws RangeError. The portal passes the caller's asOf
  to queue() and builds from view.asOf, so it accepts datetimes while
  importing only the SDK. No new SDK symbol; the doc no longer tells
  callers to reach into core.
- The portal's default-date test could fail across UTC midnight; it now
  brackets both readings and compares only when no midnight passed.
- docs/sdk-surface.md and the ADR-0031 item 8 note still described the
  portal's removed copy and bare-date rule.

New tests were observed failing first (ADR-0016), including SDK/CLI
equivalence for a datetime asOf on all four corpora.

Signed-off-by: Mark Beacom <m@beacom.dev>

* build(ci): rebuild the Action bundles after rebasing onto main, and test the portal bundle's datetime as-of

packages/ci/dist rebuilt under linux/amd64 Bun 1.4.2 on top of main (after #307, #308, #314). The portal bundle now takes the SDK's --as-of grammar: a new bundle test resolves 2026-01-08T23:30:00-05:00 to 2026-01-09, and the usage-error test uses a timezone-less datetime with core's message. Both failed against main's bundle (ADR-0016).

Signed-off-by: Mark Beacom <m@beacom.dev>

---------

Signed-off-by: Mark Beacom <m@beacom.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working gate-change-acknowledged A maintainer has seen and accepted this PR's change to the CI gate surface (ADR-0035)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lint: a schema-valid qualified reference (payments:0012) fails adr lint while every other surface treats it as inert

2 participants