Skip to content

Ignored generated Copilot output by default and added targets.copilot.commit_output to keep it tracked - #50

Merged
dzykovic merged 8 commits into
mainfrom
feature/copilot-output-ignored
Oct 7, 2026
Merged

dzykovic merged 8 commits into
mainfrom
feature/copilot-output-ignored

Conversation

@dzykovic

@dzykovic dzykovic commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Copilot was the only adapter whose generated output was committed by default: Cursor and Claude Code declare their output in .gitignore, while Copilot's .github/instructions, prompts, agents and skills were tracked. There was no reason for the difference — Copilot in the editor reads those files from disk after sync, exactly as Cursor does — and on a repository hosted outside GitHub nothing ever reads the committed copies. Generated copies in history mean review noise and drift.

Copilot now follows the same policy (decision 0020):

  • The contract ignores its four owned directories under the configured output and the legacy root copilot-instructions.md (treated like CLAUDE.md, .cursorrules and GEMINI.md). .github/ itself, workflows, templates and other hand-written files stay tracked.
  • targets.copilot.commit_output: true is the opt-in for a GitHub repository whose cloud Copilot (code review, coding agent) should read the output from the repository; init / adapter enable then withdraw exactly those lines from the CLI-managed block, never a line the project wrote above its header. Any value other than true/false is refused by sync with every output restored.
  • Contracts take the manifest as an optional second argument for Git policy only; ownership never depends on it, so the engine and the sync cache read nothing extra. A new unignore contract record names a line to withdraw.
  • status --check reports a withdrawn line still present, and every Git-policy finding that intelligence init repairs names it; a re-inclusion another rule still defeats also names git check-ignore -v to find that rule. Existing projects apply the policy with intelligence init, which prints git rm --cached for each generated file Git still tracks; the CLI never untracks anything itself.
  • AGENTS.md stays committed by default — the tool-neutral fallback every clone has before any sync — and adapter_contract_agents now says so instead of looking like an omission.

Type of change

  • CLI lifecycle or package behavior
  • Sync engine or adapter
  • Rule, agent, or skill content
  • Documentation
  • Refactor with no behavior change

Public CLI check

  • Uses only the established public command groups (no command changes; one new target field)
  • Keeps preview/apply behavior explicit for planned writes
  • Covers automatic project alignment and CI refusal through the existing suites
  • Keeps fresh-clone package restoration behind intelligence sync (unchanged)

Verification

Work in a scratch directory outside this checkout; nothing below moves the checkout or its refs. Lay out this branch's runtime first: mkdir rt && git -C <checkout> archive <this PR's head> cli engine packages | tar -x -C rt, and use bash rt/cli/intelligence as the CLI. Configure a Git identity in the scratch repository if the host has none.

  1. git init proj, create proj/.github/workflows/ci.yml (any content) and proj/intelligence/rules/scoped.md with frontmatter paths: → - "src/**" and description: "scoped", then run init --targets copilot in proj. Expected: exit 0; the CLI-managed block of proj/.gitignore lists .github/instructions/, .github/prompts/, .github/agents/, .github/skills/ and .github/copilot-instructions.md, and no line is exactly .github/; git -C proj check-ignore -q .github/instructions/scoped.instructions.md exits 0; git -C proj check-ignore -q .github/workflows/ci.yml exits 1.
  2. Change the Copilot target in proj/intelligence.yaml to copilot: { enabled: true, output: ".github", commit_output: true } and run init again. Expected: exit 0; none of the five lines remains in the CLI-managed block; git -C proj check-ignore -q .github/instructions/scoped.instructions.md exits 1. Run init once more: .gitignore is byte-identical.
  3. git -C proj add -A && git -C proj commit -qm tracked, set commit_output: false, and run init. Expected: exit 0; each of the five lines is back exactly once; the output prints git rm --cached -- '.github/instructions/scoped.instructions.md' and no git rm --cached for .github/workflows/ci.yml; nothing was untracked (git -C proj ls-files .github/instructions still lists the file).
  4. Set commit_output: yes and run sync. Expected: non-zero exit; the output says targets.copilot.commit_output must be true or false.

Automated coverage

  • unit-gitignore: default patterns including the legacy file, .github/ never ignored, opt-in withdrawal of exactly the managed lines (a project's own copy above the header kept), switching back, idempotence, CRLF and missing-final-newline preservation, a file without the header, ownership identical with and without the manifest, and an unsafe unignore path refused. These fail against the old behaviour.
  • e2e-lifecycle: fresh-init patterns, a hand-written workflow staying trackable, and a Copilot section covering the default, status --check on a stale line, opt-in, idempotence, the switch back with status --check naming intelligence init, and the git rm --cached hints. e2e-negative: a malformed value is refused and renders nothing; true renders; a deleted include negation and a defeated re-inclusion both name intelligence init, which repairs them.
  • Locally: bash cli/tests/verify.sh (run in WSL on this Windows host, since Ran local verification in WSL on Windows #42) — both lint gates and every suite passed in 2m36s.

Versioned artifacts

  • v0.18.1 is published and 0.19.0 is pending: Made status --check decide .gitignore presence with the writer's CR-blind test #55 selected it and moved the engine version, example schema versions, exact sync pins and lock entries, so this PR moves none of them and adds its lines to the existing section (a changed default existing projects must apply, which a minor version covers)
  • CHANGELOG.md ## [0.19.0] carries this change, with ### Breaking checklist items of verifiable post-conditions
  • No stable release is published by this PR

Notes for reviewers

update --apply does not re-apply Git policy; the Breaking checklist is what the upgrade skill verifies, and it names intelligence init. status --check presence checks use the CR-safe ignore_file_has_line that #55 (merged) made the single presence test; the merge of main into this branch keeps it for the ignore and include findings.

Copilot AI balanced review requested due to automatic review settings October 7, 2026 12:08

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.

Copilot review overview

🟡 Changes recommended

Some Git-policy diagnostics still omit the recovery command promised by the PR and changelog.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Makes Copilot-generated output ignored by default, with an opt-in for cloud Copilot consumers.

Changes:

  • Adds targets.copilot.commit_output and contract-level unignore support.
  • Updates Git-policy handling, diagnostics, documentation, and tests.
  • Advances versioned artifacts to 0.19.0.
File Description
README.md Documents Copilot output policy.
packages/​sync/​skills/​intelligence-learn-from-repository/​SKILL.md Updates onboarding commit guidance.
packages/​sync/​references/​onboarding-migration.md Clarifies tracked .github files.
packages/​sync/​references/​conventions.md Defines the new policy and opt-in.
packages/​sync/​references/​adapters.md Documents manifest-aware contracts and unignore.
intelligence/​rules/​engine.md Updates the adapter contract rule.
intelligence.yaml Advances schema and package version.
intelligence.lock Advances locked engine/package version.
examples/​with-remote-skills/​intelligence.yaml Advances example versions.
examples/​platform-with-submodules/​intelligence.yaml Advances example versions.
examples/​platform-with-submodules/​intelligence.lock Advances locked versions.
examples/​go-api/​intelligence.yaml Advances example versions.
examples/​go-api/​intelligence.lock Advances locked versions.
examples/​go-api-with-pi-and-codex/​intelligence.yaml Advances example versions.
examples/​go-api-with-pi-and-codex/​intelligence.lock Advances locked versions.
examples/​go-api-with-opencode/​intelligence.yaml Advances example versions.
examples/​go-api-with-opencode/​intelligence.lock Advances locked versions.
examples/​go-api-with-antigravity/​intelligence.yaml Advances example versions.
examples/​go-api-with-antigravity/​intelligence.lock Advances locked versions.
examples/​dotnet-api-with-react-frontend/​intelligence.yaml Advances example versions.
examples/​dotnet-api-with-react-frontend/​intelligence.lock Advances locked versions.
examples/​cli-project/​intelligence.yaml Advances example versions.
engine/​VERSION Selects version 0.19.0.
engine/​lib/​adapter-contract.sh Adds optional manifest and unignore records.
engine/​adapters/​copilot.sh Implements Copilot commit policy.
engine/​adapters/​agents.sh Documents intentional tracking of AGENTS.md.
engine/​adapters/​_template.sh Documents manifest-aware contracts.
docs/​cli.md Updates init and tracking behavior.
decisions/​0015-ignore-generated-copilot-output.md Records the architectural decision.
cli/​tests/​unit-gitignore.sh Tests ignore withdrawal and preservation.
cli/​tests/​e2e-negative.sh Tests invalid configuration rejection.
cli/​tests/​e2e-lifecycle.sh Tests the complete Copilot policy lifecycle.
cli/​lib/​gitignore.sh Implements managed-line removal.
cli/​lib/​adapter-lifecycle.sh Passes manifests to policy consumers.
cli/​internal/​check.sh Checks missing and stale Git policy.
cli/​commands/​init.sh Updates onboarding guidance.
CHANGELOG.md Records the 0.19.0 changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cli/internal/check.sh
@dzykovic dzykovic added the ai:processing An agent is working on this pull request label Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Code review - PASS-WITH-WARNINGS

head: 91d6b35 - base: main - files 37, +613/-76

Critical

None.

Warning

  • cli/internal/check.sh:166,169,173 - the include Git-policy findings ("Git policy is missing '!$value'", "cannot re-include … because another ignore rule still wins", "Git policy for '$value' could not be evaluated") were left unchanged and still do not name intelligence init, while the PR body's Summary ("every Git-policy finding names intelligence init") and CHANGELOG.md:18 ("every Git-policy finding names intelligence init") assert this holds for all of them. Only the ignore (check.sh:157) and new unignore (check.sh:161) cases were updated. Either narrow the claim in the body/changelog to the cases actually touched, or extend the include branch the same way.

Suggestion

None.

Summary

  • files: 37, +613/-76; critical: 0; warning: 1; suggestion: 0
  • verdict: PASS-WITH-WARNINGS

@dzykovic dzykovic added the ai:reviewed Diff reviewed on the reported head label Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Verification - PASS

head: 91d6b35 - steps: PR "## Verification" §1-4 (runtime layout + init/sync scenarios); qa_checks: none matched (docs/qa-checks.md absent) - env: local (scratch runtime laid out via git archive 91d6b358e871779c933812ab6117c7ac2ee0d11b cli engine packages | tar -x; intelligence --version reports 0.19.0 (engine 0.19.0))

# Step Source Verdict Observed
1 Fresh project, init --targets copilot: exit 0; CLI-managed .gitignore block lists the four dirs + legacy file, no literal .github/ line; .github/instructions/scoped.instructions.md ignored, .github/workflows/ci.yml not PR pass exit 0; .gitignore block = .github/instructions/, .github/prompts/, .github/agents/, .github/skills/, .github/copilot-instructions.md (no .github/ line); check-ignore on the instructions file exits 0, on the workflow exits 1
2 Set commit_output: true, re-run init: none of the five lines remain; instructions file no longer ignored; a second init leaves .gitignore byte-identical PR pass exit 0; .gitignore reduced to the two base lines; check-ignore on the instructions file exits 1; re-running init produced a byte-identical .gitignore (diff empty)
3 Commit tracked output, set commit_output: false, run init: each of the five lines back exactly once; git rm --cached printed for the instructions file, not for the workflow file; nothing actually untracked PR pass exit 0; each line present exactly once; printed git rm --cached -- '.github/instructions/scoped.instructions.md', no such line for ci.yml; git ls-files .github/instructions still lists both files
4 Set commit_output: yes, run sync: non-zero exit; error names true/false requirement PR pass exit 1; ERROR: targets.copilot.commit_output must be true or false: true keeps generated Copilot output tracked, false or omission ignores it. followed by ERROR: sync failed; all adapter-owned paths were restored to their pre-sync state.

No qa_checks entries added — docs/qa-checks.md does not exist in this repository.

Negative probes

  • Drift: with commit_output: true applied cleanly, manually re-adding a withdrawn line to .gitignore makes intelligence status --check fail: ✗ adapter 'copilot' Git policy keeps '.github/instructions/' tracked, but .gitignore still ignores it — run 'intelligence init' (exit 1) — matches the PR summary's own claim. Removing the drift returns all good. (exit 0).
  • commit_output: false (explicit) and commit_output: (empty/null) both behave exactly like omission: ignored, all five lines present, exit 0 — consistent with "false or omission ignores it".
  • Quoted scalars commit_output: "true" / "false" are quote-stripped before comparison (verified directly against get_target_field) and behave identically to the bare booleans when driven through init. Noted for the record, not a defect: the five-line .gitignore block is written/withdrawn only by init (and adapter enable|disable) — a bare sync after only editing commit_output leaves .gitignore untouched until the next init. This matches the PR's own steps (2 and 3 use init for the ignore rewrite; step 4 uses sync only to hit the value-validation error).

No failures.

@dzykovic dzykovic added the ai:verified Declared behavior verified on the reported head label Oct 7, 2026
@dzykovic dzykovic removed ai:verified Declared behavior verified on the reported head ai:reviewed Diff reviewed on the reported head labels Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Verification - PASS

head: d9107e9 - steps: PR "## Verification" §1-4 (init/sync targets.copilot.commit_output scenarios: default ignore, opt-in withdrawal + idempotence, opt-out re-ignore + git-rm-cached hints, malformed-value refusal); qa_checks: none matched (docs/qa-checks.md absent) - env: local

Runtime laid out per the PR's own instructions: git -C <checkout> archive d9107e9046dc565dcdb26aa040e5aa195a9a6ea0 cli engine packages | tar -x, confirmed built from this head (not base) by the presence of commit_output handling in engine/adapters/copilot.sh.

# Step Source Verdict Observed
1 init --targets copilot with .github/workflows/ci.yml and a scoped rule present PR pass exit 0; .gitignore CLI-managed block lists exactly .github/instructions/, .github/prompts/, .github/agents/, .github/skills/, .github/copilot-instructions.md; no .github/ line; check-ignore -q .github/instructions/scoped.instructions.md exits 0; check-ignore -q .github/workflows/ci.yml exits 1
2 Set commit_output: true, run init again PR pass exit 0; none of the five lines remains in .gitignore; check-ignore -q .github/instructions/scoped.instructions.md exits 1; a further init leaves .gitignore byte-identical
3 Commit tracked files, set commit_output: false, run init PR pass exit 0; all five lines restored exactly once each; output includes git rm --cached -- '.github/instructions/scoped.instructions.md' and contains no git rm --cached line for .github/workflows/ci.yml; git ls-files .github/instructions still lists the file (nothing was actually untracked)
4 Set commit_output: yes, run sync PR pass exit 1; stderr: ERROR: targets.copilot.commit_output must be true or false: true keeps generated Copilot output tracked, false or omission ignores it.

Negative probes (not separate steps; implied by the passing steps above)

  • A hand-written, non-owned file directly under .github (.github/CODEOWNERS) stays trackable after init --targets copilot: check-ignore -q .github/CODEOWNERS exits 1 - confirms step 1's "no line is exactly .github/" extends to a concrete file, not just the absence of that one line.
  • commit_output: "" (empty/quoted-empty) is accepted and treated as the default (false) - matches engine/adapters/copilot.sh copilot_commit_output_var, which maps '' and false to the same branch; not a defect.
  • commit_output: True (case variant) is refused with the same error as yes from step 4, and .gitignore is left unchanged - confirms the refusal isn't specific to the one literal value the step names.

No failures. All four declared steps pass; no qa_checks entries matched any PR file; no workspace block.

@dzykovic dzykovic added the ai:verified Declared behavior verified on the reported head label Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Code review - PASS-WITH-WARNINGS

head: d9107e9 - base: main - files 37, +633/-79

Critical

None.

Warning

  • cli/lib/gitignore.sh:168-186 (gitignore_read_var) and cli/lib/gitignore.sh:213-243 (gitignore_remove_managed_lines) duplicate the read/header-detection loop (cli/lib/gitignore.sh:99-112) and the write loop that preserves a missing final newline (cli/lib/gitignore.sh:120-139) already implemented inline in the sibling gitignore_collapse_duplicates (cli/lib/gitignore.sh:87) a few lines above. Same file, same change, same byte-for-byte logic (CRLF-safe read, header index, final-newline flag) under new variable names instead of factoring it once. Not a correctness bug — both paths are well covered by unit-gitignore.sh — but it is the "duplicated helpers" case the review ladder flags, and the one-source principle this repo states for itself (dev-context-engineering.md) is the same argument applied to code: the two copies agree today and are what diverge the next time either is touched. Consider having gitignore_collapse_duplicates call gitignore_read_var instead of keeping its own copy of the read loop.

Suggestion

None.

Summary

  • files: 37, +633/-79; critical: 0; warning: 1; suggestion: 0
  • verdict: PASS-WITH-WARNINGS

@dzykovic dzykovic added the ai:reviewed Diff reviewed on the reported head label Oct 7, 2026
@dzykovic dzykovic removed ai:verified Declared behavior verified on the reported head ai:reviewed Diff reviewed on the reported head labels Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Code review - CLEAN

head: a40d98c - base: main - files 37, +648/-99

No findings at any severity.

Standards axis: the .gitignore rewrite paths (gitignore_read_var, gitignore_managed_has_line, gitignore_remove_managed_lines) correctly share one CR/final-newline-preserving reader; the new unignore contract record is bounded by the same adapter_contract_safe_path check as ignore/include and excluded from the ownership-conflict scan (adapter_claims_add_records only reads owned|managed); every adapter_records_for/adapter_contract_records call site correctly passes the manifest only where Git policy is applied or checked (cli/lib/gitignore.sh:321,421, cli/internal/check.sh:138) and omits it for ownership-only reads (cli/internal/target-state.sh, cli/lib/adapter-lifecycle.sh). copilot_commit_output_var's refusal in sync_to_copilot runs before any output is touched (verified by the e2e-negative "renders nothing" case). Verified no cross-cutting drift: every reference to the new symbols (IS_GI_LINES, gitignore_read_var, adapter_contract_unignore, copilot_commit_output_var) resolves consistently across cli/ and engine/.

Claims axis: all four manual verification steps and the three automated-coverage paragraphs in the PR body match code actually present in the diff (cli/tests/unit-gitignore.sh, cli/tests/e2e-lifecycle.sh, cli/tests/e2e-negative.sh). Version lockstep (engine/VERSION, every example's schema_version/lock, intelligence.yaml/intelligence.lock) is bumped to 0.19.0 everywhere, matching release.md's rule and the stated context that v0.18.1 is already published. CHANGELOG.md's [0.19.0] section and Breaking checklist match the diff's actual behavior change. No documentation left referencing the old "commit .github/ output" default (README, docs/cli.md, conventions.md, adapters.md, onboarding-migration.md, the learn-from-repository skill all updated in the same change, per dev-context-engineering). Decision 0020 is present and consistent with the code; the 0015-0019 numbering gap is expected per provided context. No secrets in the diff.

Critical

Warning

Suggestion

@dzykovic dzykovic added the ai:reviewed Diff reviewed on the reported head label Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Verification - PASS

head: a40d98c - steps: PR "## Verification" §1-4 (init/sync targets.copilot.commit_output scenarios: default ignore, opt-in withdrawal + idempotence, opt-out re-ignore + git-rm-cached hints, malformed-value refusal); qa_checks: none matched (docs/qa-checks.md absent) - env: local (scratch runtime laid out via git -C <checkout> archive a40d98c83bd8c3988415cafdbe65fa5b0f70ef9d cli engine packages | tar -x; confirmed built from this head, not base, by decision reference 0020 in engine/adapters/copilot.sh and gitignore_collapse_duplicates calling the new shared gitignore_read_var in cli/lib/gitignore.sh)

# Step Source Verdict Observed
1 Fresh project, init --targets copilot: exit 0; CLI-managed .gitignore block lists the four dirs + legacy file, no literal .github/ line; .github/instructions/scoped.instructions.md ignored, .github/workflows/ci.yml not PR pass exit 0; block = .github/instructions/, .github/prompts/, .github/agents/, .github/skills/, .github/copilot-instructions.md (no .github/ line); check-ignore on the instructions file exits 0, on the workflow exits 1
2 Set commit_output: true, re-run init: none of the five lines remain; instructions file no longer ignored; a second init leaves .gitignore byte-identical PR pass exit 0; .gitignore reduced to the two base lines; check-ignore on the instructions file exits 1; re-running init produced a byte-identical .gitignore
3 Commit tracked output, set commit_output: false, run init: each of the five lines back exactly once; git rm --cached printed for the instructions file, not for the workflow file; nothing actually untracked PR pass exit 0; each line present exactly once; printed git rm --cached -- '.github/instructions/scoped.instructions.md' (and 16 other owned files), no such line for ci.yml; git ls-files .github/instructions still lists both files
4 Set commit_output: yes, run sync: non-zero exit; error names true/false requirement PR pass exit 1; ERROR: targets.copilot.commit_output must be true or false: true keeps generated Copilot output tracked, false or omission ignores it. followed by ERROR: sync failed; all adapter-owned paths were restored to their pre-sync state.; .gitignore left exactly as before the attempt

No qa_checks entries added - docs/qa-checks.md does not exist in this repository.

Negative probes

  • Ownership boundary: a hand-written, non-owned file directly under .github (.github/CODEOWNERS) stays trackable after step 1's init - check-ignore -q .github/CODEOWNERS exits 1, and check-ignore -q .github itself also exits 1. Confirms "no line is exactly .github/" against a real file, not just the absence of that one line.
  • commit_output value boundary: 1, False (capital F) and TRUE are all refused with the same exact error as step 4's yes, and in each case .gitignore is left unchanged - the refusal is the exact-match true/false literal, not specific to the one value the step names. commit_output: (empty) is accepted and behaves as the default (ignored) - matches "false or omission ignores it," not a defect.
  • Refactor-targeted regression probe (this commit's own change: gitignore_collapse_duplicates now reads through the new shared gitignore_read_var, which both rewriters use): built a CRLF .gitignore by hand with a project-owned line above the header, the header, .intelligence/, and the five managed .github/* lines, with no trailing newline on the file. init --targets copilot on top of it is a no-op (byte-identical, including the missing final newline - confirms idempotence survives CRLF + no-final-newline). Setting commit_output: true and re-running init removes exactly the five managed lines and leaves node_modules/\r\n, the header \r\n, and .intelligence/\r\n byte-for-byte with their CR intact (verified via xxd) - no LF corruption from the refactor that now shares the read path between gitignore_collapse_duplicates and gitignore_remove_managed_lines.

No failures. No workspace block: D:\Repositories\ainova\intelligence-copilot-ignore stayed on feature/copilot-output-ignored at a40d98c83bd8c3988415cafdbe65fa5b0f70ef9d, clean, before and after this run.

@dzykovic dzykovic added ai:verified Declared behavior verified on the reported head ai:completed Agent work completed; required factors are fresh and removed ai:processing An agent is working on this pull request labels Oct 7, 2026
…t-ignored

# Conflicts:
#	CHANGELOG.md
#	cli/internal/check.sh
#	cli/lib/gitignore.sh
@dzykovic dzykovic added ai:processing An agent is working on this pull request and removed ai:completed Agent work completed; required factors are fresh ai:verified Declared behavior verified on the reported head ai:reviewed Diff reviewed on the reported head labels Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Verification - PASS

head: 8aae84c - steps: PR "## Verification" §1-4 (fresh init --targets copilot default-ignore; opt-in commit_output: true withdrawal + idempotence; opt-out commit_output: false re-ignore + git rm --cached hints; malformed commit_output: yes refusal) - qa_checks: none matched (docs/qa-checks.md absent from this workspace) - env: local (scratch runtime laid out via git archive 8aae84c2d669a53c7f528a346889c9c276b9c8e6 cli engine packages | tar -x; confirmed built from this head, not base, by the commit_output handling in engine/adapters/copilot.sh and the ignore_file_has_line CR-safe test in cli/internal/check.sh; intelligence --version reports 0.19.0 (engine 0.19.0))

# Step Source Verdict Observed
1 Fresh proj, .github/workflows/ci.yml + scoped rule, init --targets copilot: exit 0; CLI-managed .gitignore block lists the four dirs + legacy file, no literal .github/ line; instructions file ignored, workflow not PR pass exit 0; block = .github/instructions/, .github/prompts/, .github/agents/, .github/skills/, .github/copilot-instructions.md (no .github/ line); check-ignore -q .github/instructions/scoped.instructions.md exits 0; check-ignore -q .github/workflows/ci.yml exits 1
2 Set commit_output: true, re-run init: none of the five lines remains; instructions file no longer ignored; a further init leaves .gitignore byte-identical PR pass exit 0; .gitignore reduced to the two base lines; check-ignore -q .github/instructions/scoped.instructions.md exits 1; re-running init produced a byte-identical .gitignore (diff empty)
3 Commit tracked output, set commit_output: false, run init: each of the five lines back exactly once; git rm --cached printed for the instructions file, not the workflow; nothing actually untracked PR pass exit 0; each of the five lines present exactly once; printed git rm --cached -- '.github/instructions/scoped.instructions.md', no such line for ci.yml; git ls-files .github/instructions still lists both files
4 Set commit_output: yes, run sync: non-zero exit; error names the true/false requirement PR pass exit 1; ERROR: targets.copilot.commit_output must be true or false: true keeps generated Copilot output tracked, false or omission ignores it. followed by ERROR: sync failed; all adapter-owned paths were restored to their pre-sync state.

No qa_checks entries added — docs/qa-checks.md does not exist in this repository.

Negative probes

  • Restore-on-failure: after step 4's refused sync, .gitignore was unchanged from its pre-sync (step 3) content — the refusal left no partial write.
  • Drift: with commit_output: true applied (lines withdrawn) and one withdrawn line manually re-added to .gitignore, intelligence status --check reports ✗ adapter 'copilot' Git policy keeps '.github/instructions/' tracked, but .gitignore still ignores it — run 'intelligence init' (exit 1), matching the PR summary's own claim about status --check naming the repair.

No failures.

@dzykovic dzykovic added the ai:verified Declared behavior verified on the reported head label Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Code review - CLEAN

head: 8aae84c - base: main - files 20, +605/-59

Merge resolution (CHANGELOG.md, cli/internal/check.sh, cli/lib/gitignore.sh) reviewed as part of the diff, not assumed correct: no leftover conflict markers anywhere in the tree; check.sh's ignore and include findings both now go through the CR-safe ignore_file_has_line that origin/main (#55) introduced, exactly as the PR's "Notes for reviewers" section claims; gitignore.sh kept the shared gitignore_read_var reader this PR's own prior review round (at a40d98c) asked for, rather than reverting to either side's older copy. Re-ran bash cli/tests/unit-gitignore.sh and bash cli/tests/verify.sh lint directly against this head (both pass) and smoke-tested the PR body's manual steps 1, 2 and 4 end to end against a runtime built from this exact SHA via git archive — the .gitignore managed block, check-ignore on the instructions file vs. the workflow file, the commit_output: true withdrawal, and the commit_output: yes refusal all matched the body's expected output.

Standards axis: ownership stays untouched by the new manifest argument — adapter_claims_add_records (engine/lib/adapter-contract.sh:91-100) still reads only owned|managed, cli/internal/target-state.sh and the ownership-only helpers in cli/lib/adapter-lifecycle.sh call adapter_records_for without it, while cli/lib/gitignore.sh:328,428 and cli/internal/check.sh:138 (Git-policy call sites) pass it. copilot_commit_output_var follows the same get_target_field pattern engine/adapters/codex.sh and engine/adapters/antigravity.sh already use for manifest-driven fields — no hand-rolled parsing. No secrets, no debug leftovers, no stray files in the diff.

Claims axis: decision 0020 matches the code. The PR body's four manual verification steps and three automated-coverage paragraphs match tests actually present (cli/tests/unit-gitignore.sh, cli/tests/e2e-lifecycle.sh, cli/tests/e2e-negative.sh). Version lockstep (engine/VERSION, every example's schema_version, intelligence.yaml/intelligence.lock) is 0.19.0 everywhere. v0.18.1 is published and v0.19.0 is not, so keeping the pending [0.19.0] CHANGELOG section rather than cutting a new one is correct per release.md; the merged top section (Added/Changed/Fixed/Breaking) correctly folds main's Fixed entry in alongside this PR's own Added/Changed/Breaking content, in Keep-a-Changelog order matching the file's own prior sections. No documentation (README.md, docs/cli.md, conventions.md, adapters.md, onboarding-migration.md, the learn-from-repository skill) still describes the old "commit .github/ output" default.

Critical

None.

Warning

None.

Suggestion

None.

@dzykovic dzykovic added the ai:reviewed Diff reviewed on the reported head label Oct 7, 2026
@dzykovic dzykovic removed ai:verified Declared behavior verified on the reported head ai:reviewed Diff reviewed on the reported head labels Oct 7, 2026
@dzykovic dzykovic mentioned this pull request Oct 7, 2026
9 of 13 tasks
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Verification - PASS

head: efd875d - steps: PR "## Verification" §1-4 (fresh init --targets copilot default-ignore; opt-in commit_output: true withdrawal + idempotence; opt-out commit_output: false re-ignore + git rm --cached hints; malformed commit_output: yes refusal); qa_checks: none matched (docs/qa-checks.md absent) - env: local (scratch runtime laid out via git -C <judged worktree> archive efd875d4c304b2f3e909244982fd03cf66651d16 cli engine packages | tar -x; confirmed built from this head, not base, since the commit_output handling in engine/adapters/copilot.sh:38,52-66,263-264 is absent from main; intelligence --version reports 0.19.0 (engine 0.19.0))

# Step Source Verdict Observed
1 git init proj, add .github/workflows/ci.yml and a scoped rule, run init --targets copilot. Expected: exit 0; .gitignore's managed block lists the four dirs + legacy file with no literal .github/ line; instructions file ignored, workflow not. PR pass exit 0; block = .github/instructions/, .github/prompts/, .github/agents/, .github/skills/, .github/copilot-instructions.md (no .github/ line); check-ignore on .github/instructions/scoped.instructions.md exits 0, on .github/workflows/ci.yml exits 1
2 Set commit_output: true, run init again. Expected: exit 0; none of the five lines remains; instructions file no longer ignored. A second init leaves .gitignore byte-identical. PR pass exit 0; .gitignore reduced to .intelligence/ only; check-ignore on the instructions file exits 1; second init produced the same md5 (0087632815715ba9b0ec60d2f9d37626)
3 Commit the tracked output, set commit_output: false, run init. Expected: exit 0; each of the five lines back exactly once; git rm --cached printed for the instructions file, not for the workflow file; nothing actually untracked. PR pass exit 0; each line present exactly once (verified by count); printed git rm --cached -- '.github/instructions/scoped.instructions.md' (and the other generated files), no such line for ci.yml; git ls-files .github/instructions still lists both files
4 Set commit_output: yes, run sync. Expected: non-zero exit; error names the true/false requirement. PR pass exit 1; ERROR: targets.copilot.commit_output must be true or false: true keeps generated Copilot output tracked, false or omission ignores it.; sync also reported all adapter-owned paths restored

Negative probes

  • Boundary named by step 4's own error text ("false or omission ignores it"): set commit_output: "" (empty string) and ran sync — exit 0, treated as the ignore default, .gitignore unchanged (matches engine/adapters/copilot.sh:63 case ''|false).
  • Post-failure integrity for step 4: after the malformed-value refusal, .gitignore still held the five managed lines intact (no partial write from the rejected sync).

No failures, no blocked steps.

@dzykovic dzykovic added the ai:verified Declared behavior verified on the reported head label Oct 7, 2026
@dzykovic

dzykovic commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Code review - PASS-WITH-WARNINGS

head: efd875d - base: main - files 20, +600/-63

Reviewed git diff origin/main...efd875d4 (the PR's own 20-file change set; the merge commit's unrelated upstream content - decisions 0013/0015, engine/lib/common.sh, etc. - is excluded by triple-dot). Traced the Copilot Git-policy path end to end: engine/adapters/copilot.sh's copilot_commit_output_var/adapter_contract_copilot -> engine/lib/adapter-contract.sh's new unignore record and path-safety check -> cli/lib/gitignore.sh's gitignore_read_var/gitignore_managed_has_line/gitignore_remove_managed_lines -> ensure_target_gitignore's unignore batch -> cli/internal/check.sh's new unignore warning. Hand-traced the two CRLF/no-final-newline edge cases in unit-gitignore.sh (withdrawn line in the middle vs. withdrawn line as the unterminated last line) against the implementation; both come out byte-correct, including which remaining line inherits the "no trailing newline" ending. Confirmed shellcheck --severity=warning (the actual lint-gate invocation) is clean on every touched file - the only shellcheck findings are pre-existing and in engine/adapters/_template.sh, which the lint gate already excludes by path (cli/tests/verify.sh:48). Confirmed decision 0020 matches the code point for point, v0.18.1 is published and v0.19.0 is not (gh release view), so extending the existing pending ## [0.19.0] CHANGELOG section is correct per release.md rather than cutting a new version. Checked every PR-body claim against the diff: all hold, including "sync refuses... and restores every output it touched" (the pre-existing engine/sync.sh snapshot/rollback fires because sync_to_copilot validates commit_output before touching any output) and "never a line the project wrote above its header" (gitignore_remove_managed_lines only drops indices past IS_GI_HEADER, verified against the "project's own copy above the header kept" unit test). A fresh ## Verification - PASS report already exists for this exact head and its four steps match what the code does.

Critical

None.

Warning

None.

Suggestion

  • cli/lib/gitignore.sh:134-138 and cli/lib/gitignore.sh:241-245 - gitignore_collapse_duplicates and gitignore_remove_managed_lines each reimplement the identical write loop ("print without a trailing newline only for the original last line, when the file had none"). Both already share the new gitignore_read_var for the harder read-side logic; factoring this loop into one more shared writer would leave exactly one place encoding the ending rule.
  • decisions/0020-ignore-generated-copilot-output.md:1 - ADR number 0020 leaves 0017 unclaimed: main tops out at 0016, and of the other three currently-open PRs, Let sources name a package's directories by full name or alias #48 takes 0019 and Made an unchanged sync start far fewer processes and added sync --check #54 takes 0018 while none takes 0017. Not this PR's fault alone - four branches picked numbers concurrently - and not functionally blocking, but worth an owner decision on backfilling 0017 before all four land, since adr_naming: numbered assumes a reader can rely on the sequence.

@dzykovic dzykovic added ai:reviewed Diff reviewed on the reported head ai:completed Agent work completed; required factors are fresh and removed ai:processing An agent is working on this pull request labels Oct 7, 2026
@dzykovic
dzykovic merged commit 3adf722 into main Oct 7, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai:completed Agent work completed; required factors are fresh ai:reviewed Diff reviewed on the reported head ai:verified Declared behavior verified on the reported head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants