Adopt the CLI-scaffold-parity component baseline (#11)#12
Conversation
Cargo.lock was gitignored with a rationale ("excluded until the edgecommons pin
is bumped to the UNS-core rev") that no longer held -- the pin moved to the
D-U28 rev in 49d11fd, so the gate on committing it had already been cleared.
Per the org-level lockfile-commit policy (SD-B of the component-baseline
remediation plan): regenerated with the local .cargo/config.toml [patch]
override inactive, so the lock records the git dependency
(edgecommons?rev=36a70c48...) rather than a local sibling path -- resolvable on
a fresh clone and in CI. Verified: cargo build/test/clippy all pass against
this lock with the override removed from the resolution path (isolated build,
no ancestor .cargo/config.toml), on both Windows and WSL/Linux.
This also gives issue #10's Docker-build report a lockfile CI can actually see.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxV5wFi7LCratBERVT6aiL
Cargo.toml declared license = "Apache-2.0", a stale leftover that disagreed with the actual LICENSE file (BSL 1.1 / SPDX BUSL-1.1) per org policy: all EdgeCommons repos are licensed BUSL-1.1 throughout. Also sweeps a stale comment above the edgecommons git dependency that still pointed at a `../core-monorepo/libs/rust` local-dev override path -- the current sibling layout (and the org convention) is a gitignored .cargo/config.toml [patch] override at ../core/libs/rust, not a hand-edited Cargo.toml path dependency. Fixes #9 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DxV5wFi7LCratBERVT6aiL
…mposition root out of app.rs Adds a `coverage` job to ci.yml (cargo llvm-cov --fail-under-lines 90, the same feature set the build job uses) -- the repo's ~94%/91% coverage figures were previously validated locally only; CI never gated them. Getting there honestly required a real testability fix, not just an exclusion list: `ProcessorApp::start`/`build_route`/`run` (src/app.rs) obtain a live Config/Arc<dyn MessagingService>/EventsFacade/Arc<CommandInbox>/Arc<dyn StreamService> from a real &EdgeCommons, and none of those types has a public or test constructor outside the edgecommons crate -- so this file cannot be unit-tested without a live runtime (mirrors why the protocol-adapter templates exclude their `supervisor.rs` seam, for the analogous reason of a live device driver). Everything that does NOT need &EdgeCommons directly is moved to a new src/dispatch.rs, which IS fully unit-tested: - the self-echo guard + fan-out handler (self_subscribe) - the get-stats/flush/pause/resume command verbs + panel registration - the two edge-console panels (`overview`, `routes`) -- issue #11's optional P2-6 enhancement, straightforward via the existing register_panel, so implemented rather than deferred; scope: "component" (no console instance dimension for a processor) - script-output-topic validation This crate's own src/test_support.rs adds a downstream MessagingService fake (FakeMessaging), since the library's own testutil::RecordingMessaging is pub(crate) and unreachable here. src/observe.rs's EvtEmitter gains a test-only `recording()` constructor for the same reason -- EventsFacade has no public constructor -- mirroring file-replicator's Events::recording_events precedent for the identical constraint. src/proc/route.rs's Dispatcher (already EdgeCommons-free) gains full local/northbound/stream-target/restamp/ failure-evt test coverage using the new fakes. The coverage job excludes exactly main.rs, app.rs, and test_support.rs (the last is test-only support code, not product logic -- the same treatment file-replicator gives its own testutil.rs). Measured at 92.48% lines (96 tests, cargo test/clippy -D warnings/llvm-cov all green, identical results on native Windows and WSL/Linux -- no undercount discrepancy this time). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DxV5wFi7LCratBERVT6aiL
ci.yml's paths-ignore (**.md, docs/**) means a docs-only push triggers no workflow at all today, so the docs site never refreshes until an unrelated code push happens to land alongside it. Adds the hook-guarded docs-rebuild trigger (verbatim the modbus-adapter shape): hits the Cloudflare Workers Builds deploy hook for edgecommons-docs on a docs-only push to main, a no-op until the repo's CLOUDFLARE_DEPLOY_HOOK secret is set. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DxV5wFi7LCratBERVT6aiL
…es[] `edgecommons component validate` had nothing to check this component's config against: no schema file existed anywhere in the repo, so a typo'd pipeline key was caught by no tool at any stage. Models component.global.defaults (the block edgecommons component validate currently checks) plus $defs.route/$defs.stage describing each component.instances[] entry -- the full route/pipeline-stage surface (filter, sample, aggregate, project, script incl. the multi-signal inputs/output form) -- for documentation and forward compatibility (the CLI does not yet validate instances[] against a component schema; see ec-validate's schema.rs). Deliberately does not redeclare the library envelope (logging, messaging, metricEmission, heartbeat, streaming, tags, component.token, ...), which the canonical schema owns. Validated against both shipped test-configs/ samples (component.global + every instances[] route) with a real JSON Schema validator (ajv, draft 2020-12): both pass; a typo'd key in either section is rejected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DxV5wFi7LCratBERVT6aiL
The design substance already existed (rich module-level doc headers, the monorepo's processor design docs) but the repo carried no agent-facing shape/conventions file and no in-repo design register. AGENTS.md: the processor's shape (the Processor stage seam, the app.rs/dispatch.rs testability split, config location, validation expectations) plus the org conventions it inherits. CLAUDE.md: a short header + `@AGENTS.md` import + the local-dev .cargo override note, per the org scaffold shape. DESIGN.md: a decision register (D-TP-1..8) seeded from the shipped v2 design (payload-agnostic core, external script files + the multi-signal script stage, tags-as-JSON-column) plus this remediation's own decisions (the committed lockfile, the license fix, the coverage-seam split, the console panels), the command/metrics surface, and validation evidence. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DxV5wFi7LCratBERVT6aiL
…mmons seam Adversarial review on PR #12 correctly flagged the app.rs coverage exclusion as broader than a thin live-runtime seam: build_route still contained testable decision branches (target/filter/publish-topic resolution, script-output-topic validation, the restamp policy) that need only a plain Config, not a live EdgeCommons. Moved every such decision into a new src/route_build.rs: resolve_global_wiring (cross-route defaulting + the processor's own identity strings -- previously inlined in ProcessorApp::start), resolve_target, resolve_filters, resolve_publish_topic, resolve_script_output_topics, and compute_restamp. All of it is unit-tested directly against Config::from_value-built configs -- no fake needed, since Config itself has a public test constructor (11 new tests, ~99% line coverage on the new file). What remains in src/app.rs is now only the code that must obtain a live Arc<dyn MessagingService>/EventsFacade/Arc<CommandInbox>/Arc<dyn MetricService>/Arc<dyn StreamService> (gg.streams(), stream targets only -- build_route's one remaining live dependency) or gg.shutdown_signal() from a real &EdgeCommons -- none of those types has a public or test constructor outside the edgecommons crate, so this residual is a genuine, irreducible seam, not an over-broad exclusion. ci.yml's exclusion list is unchanged ((app|main|test_support)\.rs) -- route_build.rs is deliberately NOT excluded, since it is now fully tested and belongs in the denominator. Updated AGENTS.md/DESIGN.md (D-TP-7) to describe the narrower, corrected boundary. Re-validated: cargo test 107/107 (was 96), cargo clippy -D warnings clean, cargo llvm-cov --fail-under-lines 90 -> 92.95% lines (was 92.48%), identical on native Windows and WSL/Linux. Cargo.lock untouched (verified via git diff before and after -- still git-sourced at the pinned rev; all cargo invocations for this change ran in isolated copies outside the worktree, so the ancestor .cargo/config.toml [patch] override never touched the committed lock). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DxV5wFi7LCratBERVT6aiL
|
Update: addressed an adversarial-review MINOR. The Fixed by extracting all of that into a new
Re-validated: |
Summary
Adopts the CLI-scaffold-parity component baseline for telemetry-processor. Per issue #11, this repo
is a processor, not a southbound adapter, so only the cross-cutting baseline applies (no
sb/*verbs, no
southbound_health, no device seam, no required panels). Full P0+P1+P2 per the resolvedscope decisions in the master remediation plan (SD-A: full scope; SD-B: commit the lockfile; SD-D:
fix the license mismatch inline).
Checklist (mapped to issue #11)
P0 — correctness of the reproducible build
Cargo.lock. Dropped the stale/Cargo.lock.gitignoreline + rationale;regenerated with the local
.cargo/config.toml[patch]override inactive so it records thepinned git dependency (not a local path); committed. Also unblocks issue Docker: bump the Rust build base off 1.85 (can't build current Cargo.lock) #10 (a Docker build needs
a lockfile CI can actually see).
P1 — baseline adoption
cargo llvm-cov --fail-under-lines 90added toci.yml, same featureset as the build job (
streaming,streaming-file-parquet,streaming-file-avro,scripting-lua). Gettingthere honestly required splitting
src/app.rs's untestable EdgeCommons composition root(
ProcessorApp::start/build_route/run— none ofConfig/MessagingService/EventsFacade/CommandInbox/StreamServicehas a public test constructor) from the testable fan-out/commandlogic, moved to a new
src/dispatch.rs. Added a downstreamMessagingServicefake(
src/test_support.rs) and a test-only recordingEvtEmitter(mirroringfile-replicator'sEvents::recording_events—EventsFacadehas the same no-public-constructor constraint). Thegate excludes only
main.rs,app.rs(the genuine composition-root seam), andtest_support.rs(test-only support code, same treatment
file-replicatorgivestestutil.rs).deploy-docs.yml. Added verbatim (modbus-adapter shape) so a docs-only push stilltriggers a site rebuild.
config.schema.json. Modelscomponent.global.defaults(whatedgecommons component validatecurrently checks) plus$defs.route/$defs.stagedescribing everycomponent.instances[]shape (filter/sample/aggregate/project/script, incl. the multi-signalinputs/outputform) for documentation and forward compatibility. Validated against both shippedtest-configs/samples with a real JSON Schema validator (ajv, draft 2020-12) — both pass; atypo'd key in either section is rejected.
AGENTS.md,CLAUDE.md(@AGENTS.mdimport + local-dev note),DESIGN.md(decision register D-TP-1..8 seeded from the shipped v2 design + this remediation's owndecisions).
P2 — enhancements
deferred — straightforward via the library's existing
commands.register_panel. Twoscope: "component"panels:overview(fleet totals + flush/pause/resume) androutes(per-routecounters via
get-stats).Cargo.toml'slicense = "Apache-2.0"(stale) →"BUSL-1.1"(matches the actual
LICENSEfile and org policy).Fixes #9.Cargo.tomlcomment pointing at a../core-monorepo/libs/rustsibling path (the current convention is a gitignored
.cargo/config.toml[patch]override at../core/libs/rust) fixed while touching the file.Validation
cargo test --locked --features scripting-lua: 96 passed, 0 failed (native Windows andWSL/Linux — identical results).
cargo clippy --all-targets --locked --features scripting-lua -- -D warnings: clean on bothplatforms.
cargo llvm-cov --locked --features streaming,streaming-file-parquet,streaming-file-avro,scripting-lua --ignore-filename-regex '(app|main|test_support)\.rs' --fail-under-lines 90:92.48% line coverage (gate passes), identical on native Windows and WSL/Linux — no undercount
discrepancy this run.
Cargo.lockin an isolated copy with no ancestor.cargo/config.tomloverride in scope (so it resolves the pinned git rev, exactly as CI/a realfresh clone would) —
cargo build --locked --all-targets --features scripting-luasucceeds.config.schema.jsonvalidated against bothtest-configs/*.jsonsamples with ajv (draft 2020-12).Deferred validation (per the org matrix, flagged rather than silently skipped): HOST/dual-MQTT,
GG-lab, and Kubernetes live-infra regression were not re-run. This changeset is hygiene/CI-shaped
(lockfile, coverage gate, schema, governance docs, a license fix, a testability-only source split,
and two additive console panels) — it changes no wire contract, config-consuming behavior, or
deployed runtime path, so no live-infra gate applies per the validation matrix.
Deviations from the plan
None. The
app.rs/dispatch.rssplit was not explicitly called out in the issue, but is a direct,disciplined consequence of implementing item #2 (the coverage gate) honestly rather than papering
over an untestable composition root with a broad exclusion — recorded as D-TP-7 in
DESIGN.md.Fixes #11
Fixes #9
🤖 Generated with Claude Code
https://claude.ai/code/session_01DxV5wFi7LCratBERVT6aiL