fix(source-quality): eliminate unwraps + route stdout through src/output.rs - #38
Merged
Conversation
…put.rs
Drives anc's project-mode dogfood from 90% to 97% by addressing the
findings 'anc check .' surfaces against this repo:
code-unwrap (was FAIL, now PASS):
- src/skill_install.rs:574, 613 — clap ValueEnum's to_possible_value()
is infallible by clap's contract for declared variants. Switched to
.expect("clap ValueEnum variant always has a possible value") so the
intent is documented in source.
- build.rs:70 — path.file_name() / .to_str() on a glob match are
infallible for the spec's ASCII filenames; .expect(...) calls now name
the invariant.
p7-naked-println (was 11 sites WARN, now PASS):
- New src/output.rs centralizes the binary's stdout hand-off behind
output::emit (no trailing newline) and output::emit_line (with newline).
The check's existing 'output|display in path' exemption already covers
this module by convention.
- src/main.rs:259 print! and src/skill_install.rs:510 println! now route
through output::emit / output::emit_line.
- naked_println.rs gains a build.rs exemption: cargo build scripts emit
metadata via println!("cargo:...") by required-by-protocol convention,
so flagging them produces noise without recourse. The is_cargo_build_script
predicate is precise — it walks path segments and only exempts build.rs
at a crate root, not misnamed src/build.rs / tests/build.rs files.
Tests:
- naked_println.rs: 2 new tests covering the build_script_path predicate
(positive cases: bare, relative, absolute, Windows, case-insensitive;
negative cases: src/, tests/, examples/, benches/ subtrees, and
build.rs.bak) and a check that the helper still warns at the unit level
while run() filters by path.
- All 535 existing tests still green.
11 tasks
brettdavies
added a commit
that referenced
this pull request
Apr 30, 2026
… backport (#37) ## Summary After every release tag publishes on `main` and `finalize-release.yml` flips the GitHub Release to `published`, three release-bookkeeping files are authoritative on `main` and need to flow back to `dev` so future builds from `dev` report the released version. Across `v0.1.0` → `v0.2.0` this didn't happen — `dev`'s `Cargo.toml` stayed at `0.1.0`, the `Cargo.lock` package version line stayed stale, and `dev`'s `CHANGELOG.md` was empty for the entire release history. This PR ships a tiny bash script (`scripts/sync-dev-after-release.sh`) that does the backport surgically and lands a new step in `RELEASES.md` after the publish-pipeline table making the convention explicit. Companion commit `abf1c6a` (already on `dev`) did the one-time backport for `v0.2.0` itself; this PR is purely the process change so the next release doesn't drift again. ## Changelog ### Added - `scripts/sync-dev-after-release.sh` — backports `Cargo.toml` `[package].version`, `Cargo.lock`, and `CHANGELOG.md` from `main` to `dev` after a release tag publishes. Surgical (preserves dev's other Cargo.toml lines), idempotent (re-runs are a no-op when dev is already in sync), and signed via the operator's normal commit signing — satisfies `protect-dev`'s `required_signatures` ruleset without needing a CI bot identity. ### Documentation - `RELEASES.md` § "After publish — sync ``dev`` with the release" documents the backport step, supersedes the prior "never back-merged" rule for these three specific files, and points operators at the script. ## Type of Change - [x] `chore`: Maintenance tasks (dependencies, config, etc.) - [x] `docs`: Documentation update ## Related Issues/Stories - Story: n/a - Issue: n/a - Architecture: ``RELEASES.md`` § "After publish — sync ``dev`` with the release" (lands in this PR; documents the new convention) - Related PRs: companion commit on dev ``abf1c6a chore(release): backport v0.2.0 artifacts to dev`` — applied the one-time backport that this script formalizes. Sibling PR #38 ships source-quality fixes that ride the same release as this one. ## Testing - [x] Manual testing completed - [x] All tests passing **Test Summary:** - Unit tests: n/a — pure shell glue, no Rust changes - Integration tests: n/a - Manual: ran the script's working-tree-clean guard on its own uncommitted state during development; correctly tripped (exit 65). Pre-push hook (fmt, clippy ``-Dwarnings``, test, cargo-deny, Windows compat) green on the branch. ## Files Modified **Modified:** - ``RELEASES.md`` — adds new ``### After publish — sync `dev` with the release`` subsection inside the Tagging and publishing section. **Created:** - ``scripts/sync-dev-after-release.sh`` (executable, +x). ~95 LOC bash. **Renamed:** - None. **Deleted:** - None. ## Breaking Changes - [x] No breaking changes ## Deployment Notes - [x] No special deployment steps required The script is invoked manually after each future release per the new RELEASES.md step. ## Checklist - [x] Code follows project conventions and style guidelines - [x] Commit messages follow Conventional Commits - [x] Self-review of code completed - [x] No new warnings or errors introduced - [x] Changes are backward compatible
12 tasks
brettdavies
added a commit
that referenced
this pull request
Apr 30, 2026
…ak (#39) ## Summary `target.path` in the JSON scorecard previously emitted the canonicalized absolute path from `Project::discover` (e.g. `/home/<user>/dev/agentnative-cli`). That value flows into committed scorecards under `agentnative-site/scorecards/`, README badge URLs, Show HN comment paste-throughs, and any artifact an agent posts to a PR or issue. Three PII vectors leaked through it: - **operator username** via `/home/<user>/`, `/Users/<user>/`, `C:\Users\<user>\` - **org/employer directory structure** (e.g. `/home/<user>/work/<company>/...`) - **personal directory layout intent** (`~/dev` vs `~/code` vs `~/projects`) This PR switches `target.path` to the **basename** of the resolved target — the directory name in project mode, the file name in binary mode. That carries identical identifying signal to ``tool.name`` (the slug used by `/score/<slug>` URLs and badge embeds); anything richer was information leakage with no compensating consumer use. ``command`` mode is unchanged (always `null`). No `schema_version` bump — `target.path` stays `string | null`, always-present-null contract holds, no key changes. The `schema_version` field exists to signal *shape* changes for consumer feature-detection; this is a value-content fix on an existing key. ## Changelog ### Fixed - `target.path` in `anc check --output json` now emits the basename of the resolved target instead of the canonicalized absolute path, eliminating a home-directory / username PII leak that flowed into committed scorecards, badge URLs, and agent-posted artifacts. Project mode emits the directory name (e.g. `\"agentnative-cli\"`); binary mode emits the file name (e.g. `\"anc\"`); command mode unchanged at `null`. No schema bump — value semantics changed, schema shape did not. ## Type of Change - [x] `fix`: Bug fix (non-breaking change which fixes an issue) ## Related Issues/Stories - Story: surfaced during 2026-04-30 dogfood review when the saved scorecard JSON in `.context/dogfood/` was inspected and the absolute home-dir path stood out as obvious PII leakage. - Issue: n/a — caught by inspection, not filed. - Architecture: `src/main.rs::build_target_info` is the single derivation site for `TargetInfo`; doc-comment now names the leak-vector rationale so future readers understand why basename is non-negotiable. - Related PRs: rides the next release wave alongside #37 (release backport script) and #38 (source-quality fixes), all merged into ``dev``. ## Testing - [x] Unit tests added/updated - [x] Integration tests added/updated - [x] All tests passing **Test Summary:** - Unit tests: 535 passing (no count change — the basename helper is an internal refactor, integration tests carry the new assertions). - Integration tests: ``tests/scorecard_schema_v05.rs`` — project-mode test now pins ``parsed[\"target\"][\"path\"] == \"perfect-rust\"`` (was: just ``is_string()``); binary-mode test pins ``\"test.sh\"``; new test ``schema_v05_target_path_carries_no_separators`` rejects any forward or back slash in the value (regression guard against richer path representations creeping back in). 51 tests in this suite (was 50). - Manual / dogfood: ``cargo build --release`` green; ``anc check . --output json | jq .target.path`` returns ``\"agentnative-cli\"`` (was: ``/home/brett/dev/agentnative-cli``); binary mode returns ``\"anc\"`` (was: full path); command mode returns ``null`` (unchanged). ## Files Modified **Modified:** - ``src/main.rs`` — ``build_target_info`` now uses new ``basename_string()`` helper. Doc-comment expanded with PII-leak rationale. - ``src/scorecard/mod.rs`` — ``TargetInfo`` doc-comment specifies basename semantics + leak rationale. - ``tests/scorecard_schema_v05.rs`` — tightened project + binary mode assertions to pin literal basename values; added ``schema_v05_target_path_carries_no_separators`` regression guard. - ``CLAUDE.md`` — scorecard 0.4 ``target`` bullet updated with leak rationale + pointer to the regression-guard test. **Created:** - None. **Renamed:** - None. **Deleted:** - None. ## Breaking Changes - [x] No breaking changes The schema's contract (key presence, type) is unchanged — only the value-content shape changes. Any consumer relying on absolute-path semantics was already fragile across hosts (CI's ``/runner/work/...`` vs dev's ``/home/<user>/...``); ``tool.name`` is the right field for cross-host correlation and is unaffected. ## Deployment Notes - [x] No special deployment steps required Existing scorecards committed under ``agentnative-site/scorecards/`` retain their old absolute-path values until re-scored; the next ``anc check`` run on each tool emits the basename. Site renderers that read ``target.path`` for display will show shorter strings going forward — no consumer feature-detection needed. ## Checklist - [x] Code follows project conventions and style guidelines - [x] Commit messages follow Conventional Commits - [x] Self-review of code completed - [x] Tests added/updated and passing - [x] No new warnings or errors introduced - [x] Changes are backward compatible
brettdavies
added a commit
that referenced
this pull request
May 1, 2026
## Summary v0.3.0 promotes 15 PRs from `dev` to `main`. Headline: scorecard schema bumps `0.3` → `0.5` (cumulative — `anc.commit` removed before tag), a new `anc skill install <host>` subcommand with hardened `git clone` + build-time host-map codegen, and a published agent-native badge surface (text-mode hint + JSON `badge` block) gated on a 80% eligibility floor. Plus PII fix on `target.path`, source-quality cleanup, README refresh, cross-repo sync map, and tooling-side hardening (PR template `**Renamed:**` subsection, `sync-spec` modernization, `sync-skill-fixture` drift gate, triple-diff release-flow check with squash-merge triage guidance). The release-prep also surfaced four corrections that came in via the canonical PR-to-dev flow during this ship: `#43` resynced the `skill.json` build-time fixture against upstream `agentnative-site/dev` (drift was blocking every open PR); `#42` corrected cross-repo URLs in `.github/ISSUE_TEMPLATE/` (broken since the v0.1.1 squash on `main`); `#45` replaced the release-flow's single-direction leak check with a triple-diff plus `git cherry` patch-id check (the latter caught the URL drift that motivated the change); `#46` added squash-merge-noise triage guidance to the `git cherry` step (the check produced 55 noisy `+` lines on first run, all expected, but the original comment didn't explain that). `#47` dropped the `anc.commit` field from the scorecard JSON before the v0.3.0 tag, since the `cargo:rerun-if-changed` `.git/` watches made cached builds fragile and `anc.version` is sufficient build identity. ## Changelog <!-- Per the changelog generation rules, the canonical changelog is in CHANGELOG.md. This release section reflects the same content; generate-changelog.sh extracts from each contributing PR's ## Changelog block. The bullets below are a curated highlight set for the PR body itself. --> ### Added - `anc skill install <host>` subcommand for six hosts (`claude_code`, `codex`, `cursor`, `factory`, `kiro`, `opencode`) with `--dry-run` and `--output {text,json}` flags and a uniform JSON envelope across success, error, and dry-run paths (#35). - Scorecard `--output json` self-describing metadata: four top-level blocks (`tool`, `anc`, `run`, `target`) + a `badge` block with `eligible`, `score_pct`, `embed_markdown`, `scorecard_url`, `badge_url`, `convention_url` (#34, #36). - `--output text` post-summary agent-native badge embed hint when the tool clears the 80% eligibility floor; "do not nag" rule below (#36). ### Changed - Scorecard `schema_version` bumped `0.3` → `0.4` → `0.5` (cumulative — `anc.commit` field removed before the v0.3.0 tag, see #47) (#34, #36). - `sync-spec.sh` modernized — remote-first tag resolution, `SPEC_REF` env override removed (#33). - `p7-naked-println` source check now exempts `build.rs` at any crate root (#38). - README refreshed for current state (schema 0.5, badge block, `--audit-profile`, basename `target.path`); `rust-version` bumped `1.87` → `1.88` (#34, #40). - `--output json` scorecard `anc` block no longer includes a `commit` field — `anc.version` is the build identity (#47). ### Fixed - `target.path` in `--output json` now emits the basename of the resolved target instead of the canonicalized absolute path — eliminates a home-dir / username PII leak that flowed into committed scorecards, badge URLs, and agent-posted artifacts (#39). - Eliminated four `.unwrap()` calls on infallible paths across `src/skill_install.rs` and `build.rs`, replaced with `.expect("…")` naming the contract (#38). - Cross-repo URLs in `.github/ISSUE_TEMPLATE/` corrected: spec → `agentnative`, site → `agentnative-site`, double-`cli` typo → `agentnative-cli` (#42). ### Documentation - `scripts/SYNCS.md` cross-repo sync map (#41). - `RELEASES.md` § "After publish — sync `dev` with the release" + new `sync-dev-after-release.sh` script formalizing the post-publish backport convention (#37). - `RELEASES.md` § "Releasing dev to main" step 4 replaced with a triple-diff verification block (A: main→release, B: release→dev, C: dev→main) plus a `git cherry` patch-id check (#45), with squash-merge-noise triage guidance added in #46. - README `## Install the skill` section + `[![agent-native]]` badge row (#35, #40). ## Type of Change - [x] `feat`: New feature (non-breaking change which adds functionality) - [x] `fix`: Bug fix (non-breaking change which fixes an issue) - [x] `chore`: Maintenance tasks (dependencies, config, etc.) - [x] `docs`: Documentation update ## Related Issues/Stories - Story: v0.3.0 release — twelve PRs across two days of work post-v0.2.0 plus four release-prep PRs (#42, #43, #45, #46) opened during the release ceremony to fix issues caught by the new triple-diff verification, plus #47 dropping `anc.commit` before the tag. - Issue: n/a - Architecture: scorecard schema evolution (`0.3 → 0.4 → 0.5`) covered in CLAUDE.md `## Scorecard v0.5 Fields`; skill-install architecture covered in CLAUDE.md `## Skill Install Verb`; release ceremony in `RELEASES.md`. - Related PRs: #30, #33, #34, #35, #36, #37, #38, #39, #40, #41, #42, #43, #45, #46, #47 — all merged to `dev` and cherry-picked here in chronological order. ## Testing - [x] Unit tests added/updated - [x] Integration tests added/updated - [x] Manual testing completed - [x] All tests passing **Test Summary:** - Unit tests: 535+ passing across all #34, #35, #36, #38, #39 PRs (counts varied as PRs landed). #47 simplified to ~520+ after dropping the `anc_commit_when_present_looks_like_short_sha` test. - Integration tests: full suite green at every cherry-pick step. New tests added: `tests/scorecard_metadata_security.rs` (red-team regressions for hostile binaries), `tests/scorecard_schema_v05.rs` (schema drift guard with `target.path` regression test), `tests/skill_install.rs` (10 active + 1 ignored e2e), `tests/dogfood.rs` (p2/p5 dogfood guards). - Coverage: pre-push hook (CI mirror) green at every step — fmt, clippy `-Dwarnings`, full test suite, cargo-deny, Windows compat (libc grep + cross-target clippy). - Triple-diff verification (the new step from #45) confirmed only `docs/plans/`, `docs/brainstorms/`, `docs/ideation/` (guarded paths) and the `docs/solutions` symlink remain on dev. Release-prep files (`CHANGELOG.md`, `Cargo.{toml,lock}`, `completions/*`) will backport to dev via `scripts/sync-dev-after-release.sh` post-publish per the convention from #37. The `git cherry` patch-id check produced 55 `+` lines on first run; all audited as expected (squash-merge patch-id mismatch + conflict-resolution drift + intentional skips), zero real misses — motivated #46's triage guidance. ## Files Modified **Modified:** - `Cargo.toml`, `Cargo.lock` — version `0.2.0 → 0.3.0`; `time = "=0.3.47"` added; `rust-version` bumped. - `CHANGELOG.md` — v0.3.0 release notes prepended. - `README.md`, `AGENTS.md`, `CLAUDE.md` — updated for schema 0.4/0.5, skill-install architecture, audit-profile, basename `target.path`, badge surface, `anc.commit` removal. - `RELEASES.md` — post-publish backport step (#37); skill-fixture sync step; step 4 replaced with triple-diff + `git cherry` check (#45); squash-merge triage guidance added (#46). - `build.rs` — `emit_skill_hosts` codegen, `ANC_VERSION` emission (no longer Git-SHA-aware after #47). - `src/build_info.rs` — `ANC_VERSION` re-export; `ANC_COMMIT` and its test removed in #47. - `src/main.rs`, `src/cli.rs`, `src/error.rs`, `src/scorecard/mod.rs`, `src/argv.rs` — schema 0.4/0.5 metadata, skill-install dispatch, badge computation, basename helper. `AncInfo` shrinks to one field after #47. - `src/checks/source/rust/naked_println.rs` — build.rs exemption. - `src/skill_install/skill.json` — fixture refresh (`source.commit` pin and `verify` block removed by upstream). - `scripts/sync-spec.sh` — remote-first, `SPEC_REF` removed. - `scripts/hooks/pre-push` — Windows cross-clippy step. - `.github/pull_request_template.md` — `**Renamed:**` sub-header. - `.github/ISSUE_TEMPLATE/{config,false-positive,feature-request,scoring-bug}.yml` — corrected cross-repo URLs. - `completions/anc.{bash,zsh,fish,elvish,powershell}` — regenerated. **Created:** - `src/output.rs`, `src/skill_install.rs`, `src/skill_install/skill.json`. - `tests/dogfood.rs`, `tests/scorecard_metadata_security.rs`, `tests/scorecard_schema_v05.rs`, `tests/skill_install.rs`, `tests/fixtures/hostile-{hang,nonzero-exit,stdout-flood}/probe.sh`. - `scripts/sync-skill-fixture.sh`, `scripts/sync-dev-after-release.sh`, `scripts/SYNCS.md`. - `.github/workflows/skill-fixture-drift.yml`. - `.github/ISSUE_TEMPLATE/00-blank.yml`. **Renamed:** - `tests/scorecard_schema_v04.rs` → `tests/scorecard_schema_v05.rs` (drift guard now covers `badge.*` keys). - `tests/fixtures/skill.json` → `src/skill_install/skill.json` (codegen needs to read from a path inside cargo's package). **Deleted:** - `.github/ISSUE_TEMPLATE/grade-a-cli.yml`, `pressure-test.yml`, `spec-question.yml` — duplicates of the spec repo's set; routed via `config.yml`. - `src/build_info.rs::ANC_COMMIT` const (and its test) — dropped before tag, see #47. ## Breaking Changes - [x] No breaking changes The scorecard `schema_version` bumps (`0.3` → `0.4` → `0.5`) are additive within the documented `0.x` pre-launch policy. Pre-`0.4` consumers feature-detect the four metadata blocks; pre-`0.5` consumers feature-detect the `badge` key. `target.path` value semantics changed (basename instead of absolute path) — schema shape is unchanged, so consumers reading the field at all will continue to parse it; consumers using it for cross-host correlation should already have migrated to `tool.name`. `anc.commit` was added in 0.4 but removed before the v0.3.0 tag (#47); no public consumer of the field exists pre-launch. ## Deployment Notes - [x] No special deployment steps required Standard pipeline: tag push triggers crates.io publish (Trusted Publishing, OIDC), GitHub Release with all 5 platform archives + sha256sums, then dispatch to `brettdavies/homebrew-tap` for formula update. After `finalize-release.yml` flips `make_latest: true`, run `./scripts/sync-dev-after-release.sh v0.3.0` to backport `Cargo.toml`, `Cargo.lock`, `CHANGELOG.md` to dev (new convention from #37). ## Checklist - [x] Code follows project conventions and style guidelines - [x] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) - [x] Self-review of code completed - [x] Tests added/updated and passing - [x] No new warnings or errors introduced - [x] Changes are backward compatible (or breaking changes documented)
brettdavies
added a commit
that referenced
this pull request
May 28, 2026
…st-revised dates Pulls the date-discipline fix from agentnative-spec PR #38 (`fix(principles): enforce last-revised discipline + backfill stale dates`). Seven principle files refresh their `last-revised` frontmatter to match the date their content actually changed; p3 was already correct and stays as-is. The applicability semantics already vendored at `b4f4d02` (U1 of the scorecard fairness taxonomy plan) carry through unchanged; this is a frontmatter-only update. VERSION still reads `0.4.0` because the upstream spec defers the cut to a release PR; the resync is faithful. No source changes here; the regenerated `REQUIREMENTS` slice via `build.rs` is byte-identical to the prior build because the parser does not consume `last-revised`. Resolved short SHA: 1fb49fe (printed by sync-spec.sh during vendoring).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Dogfooding
anc check .against this repo on the v0.2.0 binary surfaced one FAIL and one multi-site WARN thattogether pulled the project-mode score down to 90%. This PR addresses both, taking the score to 97% with 0 fail
/ 1 warn (the remaining warn is
p2-json-output's known probe limitation:--help/--versionshort-circuit--outputflags, so safe probes can't validate the JSON envelope; that's a check-design concern, not a realregression).
Two related cleanups, plus the supporting refactor:
.unwrap()sites are infallible by upstream contract: clap'sValueEnum::to_possible_value()always returnsSomefor declared variants (src/skill_install.rs:574, 613), andPath::file_name()/OsStr::to_str()on a glob-matched ASCII filename inbuild.rscannot fail in practice. Allthree are now
.expect("…")calls naming the invariant in source so the next reader doesn't have to reconstructthe reasoning.
println!("cargo:rerun-if-changed=…")andprintln!("cargo:warning=…")directives; there's no other API. Thep7-naked-printlncheck now exemptsbuild.rsat any crate root via a precise path-segment predicate (rejects misnamedsrc/build.rs,tests/build.rs, etc).boundary. New
src/output.rscentralizes them behindoutput::emit(no trailing newline) andoutput::emit_line(with newline). The check's existingoutput|display in pathexemption already covers thenew module by convention, so no check change is needed for this case.
Changelog
Changed
p7-naked-printlnsource check now exemptsbuild.rsat any crate root. Cargo build scripts useprintln!("cargo:…")directives by protocol; flagging them produces noise without an alternative API. Misnamedsrc/build.rsortests/build.rsfiles stay flagged.Fixed
.unwrap()calls on infallible operations acrosssrc/skill_install.rsandbuild.rs. Replacedwith
.expect("…")naming the upstream contract that guaranteesSome/Ok. No behavior change; these werealready infallible, and the
expectmessages document why.Type of Change
fix: Bug fix (non-breaking change which fixes an issue)Related Issues/Stories
anc check .dogfood, not a filed issue).src/output.rsbecomes the single stdout hand-off point for the binary;src/checks/source/rust/naked_println.rsexempts build scripts at any crate root.Testing
Test Summary:
naked_println.rscoveringis_cargo_build_scriptpredicate: positive cases bare/relative/absolute/Windows/case-insensitive; negative cases src/, tests/, examples/, benches/ subtrees andbuild.rs.bak; plus an integration check that the helper still warns at unit level whilerun()filters by path).anc check .reports 33 checks: 28 pass, 1 warn, 0 fail, 4 skip → 97% (was 90%). Binary mode unchanged at 89% (orthogonal to source-side findings).cargo fmt --check,cargo clippy --release -- -Dwarnings, full pre-push hook all green.Files Modified
Modified:
build.rs:.unwrap().to_str().unwrap()chain →.expect("…")calls naming the invariant.src/checks/source/rust/naked_println.rs:is_cargo_build_scripthelper exempts crate-root build scripts; doc-comment on the module updated; 2 new tests.src/main.rs: declares the newoutputmodule; routes the final stdout hand-off throughoutput::emit.src/skill_install.rs: two test-side.unwrap()→.expect()replacements;println!("{rendered}")→crate::output::emit_line(&rendered).Created:
src/output.rs: single stdout hand-off point withemitandemit_linehelpers.Renamed:
Deleted:
Breaking Changes
The naked-println exemption broadens what passes; no tool that previously passed will now fail.
Deployment Notes
Checklist