Skip to content

Lane A (A.14-A.16): delta ingestion, weekly self-heal, schema-drift handling - #12

Merged
tom-snyder merged 1 commit into
mainfrom
feat/phase3-lane-a-record
Aug 10, 2026
Merged

Lane A (A.14-A.16): delta ingestion, weekly self-heal, schema-drift handling#12
tom-snyder merged 1 commit into
mainfrom
feat/phase3-lane-a-record

Conversation

@tom-snyder

Copy link
Copy Markdown
Member

Summary

Three of the eight packets in this batch. A.17A.21 were killed by the session cap before writing anything — checked against the filesystem per §0.3, and unlike the R.2 case earlier in this build they left no partial artifacts, so they're not-started rather than half-done.

A.14 — steady-state delta ingestion

Every clock comes from the A.1 feed row, enforced by an AST test verified RED against synthetic source. Reconcile and baseline are window-boundary tests via time.Truncate, not elapsed-time tests — "end-of-day delta once daily" has to fire when the UTC day changes, and a feed polled at 23:50 then 00:10 crosses the boundary where an elapsed-time test would never fire on a busy feed.

The delta cursor is a query, not a stored column, so it can't disagree with the data the way a cursor that advanced past a failed write would. Exactly one thing crosses from feed content into a request — a CVE id that passed an allowlist — and DeltaLogRecord has no field for the log's own githubLink, enforced by a reflection test so a later change can't quietly start following it.

Two guards are allowlists, not denylists — now this project's default after three denylists were defeated by a symbol, a verb and a wording nobody listed. A SQL allowlist makes a full FTS rebuild unreachable (14 forbidden statements refused, including two a verb denylist misses); a CVE-id allowlist refuses traversal in three encodings, scheme, authority, NUL, CRLF smuggling and Arabic-Indic digits.

A defect its own guard caught mid-build, and it's the exact shape this project keeps finding: IsCVEID trims whitespace before judging, so the string checked was not the string used and "CVE-2024-0001 " was accepted. Input must now be canonical already and is used byte-for-byte as accepted.

A.15 — weekly self-heal

It reports what it found rather than silently repairing. A self-heal that repairs quietly is indistinguishable from one that never runs — and a disagreement between the baseline and the delta-built cache is a signal about the delta path, not noise to absorb.

A.16 — schema drift

Branches on CVE dataVersion explicitly and makes an unknown version a loud degraded state carrying which fields weren't understood, setting S6's parse_degraded. A parser that skips an unrecognised field and emits anyway produces a finding that looks whole and isn't.

One decision escalated — ruled as §6.1 (G11)

A.14 couldn't edit internal/ingest/bootstrap, whose decoders are unexported, so it re-derived CVE 5.x / OSV / KEV decoding. Two producers writing one table from one wire format.

Worse than it looks: if they diverge, A.15's weekly self-heal restores the same rows forever and nothing surfaces it. A self-healing system healing toward the wrong answer is quieter than one that breaks.

A.14 did the right thing available to it — a conformance test running both importers over the same fixtures, comparing every byte-derived column of advisory, affected and cve_alias. But two implementations agreeing today is a smoke alarm, not a fix. Ruling: extract one shared decode package, owned by A.21, the first step permitted to edit both.

Also recorded and not a defect: SyncReconcile refuses by default and should stay that way. A.8's resolveArchiveURL picks the largest archive asset — the 570 MB midnight baseline, not the ~17 MB end-of-day delta — so wiring reconcile to it would cost 570 MB/day and would silently be the re-download A.14's packet forbids.

Testing

gofmt / vet / build   clean
go test -count=1      green across all packages

No new dependencies. No t.Skip added, so internal/SKIPPED-CONTROLS.md is unchanged.

…andling

Three of the eight packets in this batch. A.17-A.21 were killed by the Anthropic
session cap before writing anything -- checked against the filesystem per
IMPLEMENTATION-PLAN section 0.3, and unlike the R.2 case earlier in this build
they left NO partial artifacts, so they are not-started rather than half-done.

A.14 steady-state delta ingestion. Every clock comes from the A.1 feed row --
interval, reconcile and baseline -- and an AST test verified RED against
synthetic source enforces that no duration is written in Go. Reconcile and
baseline are WINDOW-BOUNDARY tests via time.Truncate rather than elapsed-time
tests, because "end-of-day delta once daily" must fire when the UTC day changes:
a feed polled at 23:50 and again at 00:10 crosses the boundary, and an
elapsed-time test would never fire on a busy feed.

The delta cursor is a QUERY rather than a stored column, so it cannot disagree
with the data the way a cursor that advanced past a failed write would. Exactly
one thing crosses from feed content into a request -- a CVE identifier that
passed an allowlist -- and DeltaLogRecord has no field for the log's own
githubLink, which a reflection test enforces so a later change cannot start
following it.

Two guards are allowlists rather than denylists, which is now this project's
default after three denylists were defeated by a symbol, a verb and a wording
nobody listed: a SQL allowlist that makes a full FTS rebuild unreachable
(14 forbidden statements refused, including two a verb denylist misses), and a
CVE-ID allowlist that refuses traversal in three encodings, scheme, authority,
NUL, CRLF smuggling and Arabic-Indic digits.

A defect its own guard caught mid-build, worth recording because it is the exact
shape this project keeps finding: IsCVEID trims whitespace before judging, so
the string CHECKED was not the string USED and "CVE-2024-0001 " was accepted.
Now the input must already be canonical and is used byte-for-byte as accepted.

A.15 weekly full-baseline self-heal. It REPORTS what it found rather than
silently repairing, because a self-heal that repairs quietly is
indistinguishable from one that never runs -- and a disagreement between the
baseline and the delta-built cache is a signal about the delta path, not noise.

A.16 feed-schema-drift. Branches on CVE dataVersion explicitly and makes an
unknown version a loud degraded state carrying which fields were not understood,
setting S6's parse_degraded. A parser that skips an unrecognised field and emits
anyway produces a finding that looks whole and is not.

One decision escalated, ruled in section 6.1 (G11)

A.14 could not edit internal/ingest/bootstrap, whose decoders are unexported, so
it re-derived CVE 5.x / OSV / KEV decoding -- two producers writing one table
from one wire format. Worse than it looks: if they diverge, A.15's weekly
self-heal restores the same rows FOREVER and nothing surfaces it. A
self-healing system healing toward the wrong answer is quieter than one that
breaks.

A.14 did the right thing available to it -- a conformance test running both
importers over the same fixtures and comparing every byte-derived column -- but
two implementations agreeing today is a smoke alarm, not a fix. Ruling: extract
one shared decode package, owned by A.21, the first step permitted to edit both.

Also recorded and NOT a defect: SyncReconcile refuses by default and should stay
that way. A.8's resolveArchiveURL picks the LARGEST archive asset, which is the
570 MB midnight baseline rather than the ~17 MB end-of-day delta, so wiring
reconcile to it would cost 570 MB/day and would silently BE the re-download
A.14's packet forbids.

Evidence: gofmt, vet, build clean; go test -count=1 ./... green across all
packages. No new dependencies, no t.Skip added, so
internal/SKIPPED-CONTROLS.md is unchanged.
@tom-snyder
tom-snyder merged commit 1e8009b into main Aug 10, 2026
5 checks passed
@tom-snyder
tom-snyder deleted the feat/phase3-lane-a-record branch August 10, 2026 04:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant