Skip to content

Detect a Bare secrets/ Directory From the Tracked Files That Name It - #3838

Merged
ptr727 merged 28 commits into
developfrom
burndown/3719-bare-secrets
Nov 3, 2026
Merged

ptr727 merged 28 commits into
developfrom
burndown/3719-bare-secrets

Conversation

@ptr727

@ptr727 ptr727 commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Summary

The runtime-secrets audit dimension never reported a bare secrets/ directory. A runtime-secrets directory is ignored by design, so it holds no tracked path, and secret_stem_findings judged tracked paths only. The check now reads the tracked files that name such a directory instead.

  • The bare directory. secrets.stems reads each tracked .gitignore and each compose or editor config file (compose*.yml, docker-compose*.yml, .vscode/*.json, .devcontainer configs). A compose file is read by its YAML keys, for the paths compose resolves on the host. A .gitignore line ignoring a directory named secrets (secrets/, /secrets, **/secrets/, secrets/*), or a repo-relative secrets/<name> path, reports the bare directory with each file naming it. .secrets is never matched. A container mount point such as /run/secrets/<name> is out of scope, and so is a path that climbs out of the repository.
  • A file the repository names but does not track. Each secret file such a path names, in secrets/ or .secrets/, is judged by the env and secret file rule even though the tree lacks it. A compose path resolves against its own directory, and an editor path against the workspace root. A file the tree tracks, or whose .example it tracks, is judged once, from the tree.
  • The .txt rule. A .txt extension on a file in a secrets directory now breaks the rule, per GOVERNANCE.md "Repo-Scoped Secrets" (a single opaque credential carries no extension). It applies to tracked and named files alike.
  • A directory that tracks code is not one. A reference into a secrets directory that tracks more than its own .gitignore, .gitkeep, README.md, templates, and files beside their templates is no signal, since that directory is not ignored. A bare directory's own tracked files report it.
  • Only a marked path counts. A path counts where a ./, ../, or workspace variable marks it, or where it is a compose file: value. A URL path, a cloud resource name, a Vault path, or a shell $PWD is not one. A whole-directory mount counts. A relative editor path reports the directory but judges no file name, since it depends on a task's working directory.
  • A .gitignore line counts where it ignores the folder or its files by glob, and an anchored one inside a code directory does not.
  • A named file is counted once however many files name it, and is listed with each of them.
  • A signal file whose read returns no text is reported as undecided rather than read as clean.

The issue's constructed case is the end-to-end test in tests/test_audit.py. The parser and regex edges are in tests/test_audit_helpers.py. spec/project-types.json already states both the bare directory and the .txt file as drift, so its assert text needs no change.

Local review findings

Every introduced finding the local passes raised is fixed or filed, through 266f99f6. The last pass, at 266f99f6, raised one finding, deferred:

Declined findings

  • spec/project-types.json:175, introduced: a host-side home path such as ~/.secrets/Api_Token.txt is not judged. Declined. AUDIT.md section 7's runtime-secrets bullet leaves host-side names to hand judgment: "The rest is judged by hand. ... A host-side name is judged where the repo's docs and scripts spell it out, never by reading a host."

Pre-existing findings, filed

Follow-ups filed

Closes on promotion: #3719

🤖 Generated with Claude Code

ptr727 and others added 3 commits November 2, 2026 13:32
The runtime-secrets check read only tracked paths, and a runtime-secrets
directory is ignored by design, so a bare secrets/ never reached it.
secrets.stems now also reads the tracked .gitignore, compose, and editor
config files. A .gitignore line ignoring a directory named secrets, or a
repo-relative secrets/<name> path, reports the bare directory. Each
secret file such a path names that the tree lacks is judged by the env
and secret file rule, and a .txt in a secrets directory now breaks it.
A container mount point such as /run/secrets/<name> is left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng It

A bare secrets/ directory holding its own tracked .gitignore, .gitkeep,
or .example template is now reported, and each template in it judged.
A compose file is told from an editor config by its name, so one under
.devcontainer resolves against its own directory. A path to a tracked
file is no signal. A name stops at a colon, drops trailing dots, and is
judged only when it is a plain file name. The devcontainer and shell
workspace variables, nested and root devcontainer configs, and a
backslashed editor path are read. A nested workspace resolves against
its own root.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A reference into a secrets directory that tracks more than its own
.gitignore, .gitkeep, README.md, and templates is no signal, since that
directory is not ignored. That covers a directory, a glob, and a path
with trailing prose punctuation, not only an exact tracked file. A
named secret file is keyed on its resolved path, so two files naming
one count it once and are both listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings November 2, 2026 21:48
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 7f188fa96f620b10faa92c0a36221abb6d58ebc4, the content this pull request carries at that commit against develop, and it recorded 5 findings.

A secrets directory named with no file after it, such as a compose
./secrets:/run/secrets mount or a devcontainer bind, now reports the
bare directory, while a bare word or a secrets: key does not. A path
below a directory the tree lacks, such as a URL path or a cloud
resource name, is no repo path. Only a secrets directory tracking more
than its own files and templates, at any depth, counts as code, and
that now also exempts its held templates and an anchored .gitignore
line inside it. A relative editor path depends on a task's working
directory, so it reports the directory but judges no file name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.39394% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.29%. Comparing base (b38e084) to head (266f99f).
⚠️ Report is 84 commits behind head on develop.

Files with missing lines Patch % Lines
spec/audit.py 99.39% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3838      +/-   ##
===========================================
+ Coverage    81.60%   83.29%   +1.68%     
===========================================
  Files           26       29       +3     
  Lines         9070     9933     +863     
===========================================
+ Hits          7402     8274     +872     
+ Misses        1668     1659       -9     
Flag Coverage Δ
python-3.13 83.29% <99.39%> (+1.68%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…Folder

$PWD, ${PWD}, and $(pwd) name whatever directory a task or a compose
run starts in, so they are no repo path. A .gitignore line counts only
where it ignores a secrets folder itself or every file in it, and a
floating line counts only where no code directory named secrets sits
below it. A workflow file is no compose file whatever its name. The
walk over each path's secrets folders runs once, in secret_folders,
which now also returns the files a bare directory holds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Several moderate active findings in spec/audit.py leave valid secrets references undetected or misclassified, so the changes require fixes before approval.

5 open issues
What changed in this PR

This pull request expands the runtime-secrets audit to detect bare secrets/ directories and validate named secret files from tracked configuration files, including untracked files. It also enforces the .txt restriction for opaque credentials and reports unreadable signal files as undecided.

Changes:

  • Parses .gitignore, Compose, VS Code, and Dev Container configuration references.
  • Adds path resolution, deduplication, template, mount, and directory handling.
  • Adds end-to-end and helper tests for the expanded audit behavior.
  • Review findings remain in spec/audit.py: five P1 moderate findings with 4 votes each concerning path-context parsing, directory-only references, nested .secrets templates, code-directory exemptions, and editor options.cwd; plus one P2 moderate finding with 1 vote concerning structured-format parsing.
File Description
tests/​test_audit.py Adds fake GitHub responses and end-to-end coverage for tracked signals naming a bare secrets/ directory.
tests/​test_audit_helpers.py Adds parser, naming, path-resolution, deduplication, directory, template, and unreadable-input coverage.
spec/​audit.py Implements signal-file scanning, bare-directory detection, named secret validation, .txt enforcement, and unreadable-file reporting. Contains the six recorded review findings described above.

Review effort: Lite

Comment thread spec/audit.py Resolved
Comment thread spec/audit.py Resolved
Comment thread spec/audit.py Resolved
Comment thread spec/audit.py Resolved
Comment thread spec/audit.py Resolved
…ts Template

A path into a secrets directory counts only where a ./, ../, or
workspace variable marks it, or where it is a compose file: value, so a
Vault path or prose naming secrets/ is no signal. A .gitignore line
counts where every segment past the folder is a glob, so secrets/**/*
reads as the folder. A file beside its own template is one of the
directory's own files, so a committed credential no longer makes a bare
directory read as code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head edd48d886da1849545bd5f1c5c25959e6571d624, the content this pull request carries at that commit against develop, and it recorded 3 findings.

ptr727 and others added 3 commits November 2, 2026 14:11
…the Move

A compose path counts only on a line compose resolves on the host, a
list item or a file, env_file, source, or context key, quoted or not.
So a container-side environment or command value is no repo path, and
a quoted file: value with no ./ is read. A .gitignore line is no signal
once the tree or that file names a .secrets directory, since a repo
that moved keeps the old line to guard existing checkouts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pace Variable

Whether compose resolves a value on the host depends on its key, not on
how its line starts. So a compose file is now parsed, and only its
secret and config files, env files, bind sources, and build contexts
are read. A command or healthcheck list item and a named volume are no
repo path, and a long-syntax bind source and an env_file path entry
are. An editor path counts only under a workspace variable, since any
other depends on a launch's working directory. A compose file that
does not parse is reported as undecided.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed by a Path

A compose file carrying the !reset or !override tag now parses rather
than reading as undecided. A path ending at a tracked file named
secrets names no directory, and one ending at a tracked directory is
not judged as a secret file. A .gitignore is no longer fetched once the
tree carries a .secrets directory, since its lines would be discarded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head d06b66fa2b3bd6cf3e84fd38f96ec7919b659d6c, the content this pull request carries at that commit against develop, and it recorded 5 findings.

ptr727 and others added 2 commits November 2, 2026 14:34
The compose read now goes through the existing _yaml helper, which
takes a loader, rather than a second parser of its own. A compose file
that does not parse, such as a Jinja template, is no signal rather than
a standing undecided finding nothing could clear. The compose name
pattern no longer matches composer.yml. An editor path rooted by
${workspaceRoot} or ${fileWorkspaceFolder} is read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A // comment line in an editor file is no live path, so a disabled
mount or envFile no longer reports. An anchored .gitignore line now
goes through secret_path_target like every other signal, so one below a
directory the tree lacks, or naming a tracked file called secrets, is
no signal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 185c12532f66973d34727576c11b0ca8889fc408, the content this pull request carries at that commit against develop, and it recorded 1 finding.

ptr727 and others added 3 commits November 2, 2026 14:48
A // comment after a code line in an editor file is now dropped like
one opening a line, so a commented-out old secrets/ path no longer
reports a bare directory. A // inside a URL, after a colon, is kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fleet keeps its VS Code settings in a root .code-workspace file,
which can also carry launch and task entries, so the check now reads
one. A compose bind source or build context and a devcontainer mount
source may be directories, so each reports the secrets folder but no
longer judges its last segment as a secret file name. Compose secret,
config, and env files are still judged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A devcontainer config names paths mostly as mounts, run arguments, and
commands, any of which may be a directory, in more forms than one
pattern could tell apart. So a devcontainer path now reports the
secrets folder but judges no file name, as a compose bind source does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 94ae51a4aaadb8cf76ad8b5e9122d2a0dc873892, the content this pull request carries at that commit against develop, and it recorded 2 findings.

ptr727 and others added 2 commits November 2, 2026 15:07
…tor Name

A .code-workspace file's ${workspaceFolder} now resolves against the
first folder its folders entry lists, and a file whose folder climbs
out of the repo is not read. An editor path may be a directory, as a
docker run -v bind in a task is, so its last segment is judged as a
secret file name only where it carries an extension, which a directory
rarely does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne's Prefix

A compose secret, config, or env file path ending at secrets names a
file, so it no longer reports a bare directory. A floating .gitignore
line with a glob before the folder, such as legacy/*/secrets/, now
counts only where its literal leading directories exist, as the same
line without the glob already did. The two path patterns share one
folder fragment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 3fa8ad8c2ea92a1c7dd9567ca7d1b5be32d5db75, the content this pull request carries at that commit against develop, and it recorded 1 finding.

A floating .gitignore line such as deploy/**/secrets/ was silenced by a
code secrets/ directory anywhere below the .gitignore, including one
the line cannot match. The check now looks below the line's literal
prefix, and below the .gitignore's directory only where the line has
none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A sentence period after an extensionless editor path passed the
extension test, so a directory named in prose was judged as a secret
file. The test now reads the name with its trailing dots dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 33ee6c270a94df2317a0cae3f3cfb1768baf5a02, the content this pull request carries at that commit against develop, and it recorded 1 finding.

ptr727 and others added 2 commits November 2, 2026 15:38
The secret_stem_findings docstring said only the templates directly in
a bare secrets/ directory are judged. Every file directly in it other
than its README.md, .gitignore, and .gitkeep is, a committed credential
beside its template included, and the docstring now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The case meant to show an anchored .gitignore line taking the same
refusals as other paths also tracked a .secrets template, so the
check skipped its .gitignore and the case proved nothing. Without the
template the .gitignore is read, and dropping the refusals now fails
the case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 4e30cb3bc6db546731868ee24f1f66179d9ea92e, the content this pull request carries at that commit against develop, and it recorded 11 findings.

ptr727 and others added 2 commits November 2, 2026 15:54
A .gitignore was dropped as moved when any line named .secrets, a
comment line included, so a note beside a live secrets/ line hid it.
Comment lines are now skipped there. The .. guards and the **/ test,
which other clauses already decided, are gone. A case now fails
without each remaining guard: the moved drop, a tracked directory, the
devcontainer no-name rule, a named volume, a plain path past the
folder, an exempt file, the trailing-period strip, and the workflow
exclusion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A held file's folder is never in holding, so testing it again was dead.
A case now fails without the .gitignore negation guard, the reference
pattern's segment-end lookahead, the plain file name check, the compose
build context, and the compose configs section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 52ceb94685b973f8589c846d2f85439a84f0a983, the content this pull request carries at that commit against develop, and it recorded 1 finding.

ptr727 and others added 2 commits November 2, 2026 16:10
The cwd-relative case also carried a workflow file named like a compose
file, but its text has no key compose reads, so the case passed with
the workflow exclusion removed. The dedicated not-read test is what
pins that exclusion, so the fixture and its label clause are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An editor path written with ${/} or ${pathSeparator} between its parts
is now read like one written with /. A case now fails without the
string form of a compose build, a negated .secrets line marking a
.gitignore as moved, and the template guard on an editor-named file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 761613bae052c5e3223e14818d720e8f79ebf316, the content this pull request carries at that commit against develop, and it recorded 5 findings.

ptr727 and others added 2 commits November 2, 2026 16:29
…ranches

ignored_secrets_folder's second value is true only for a line anchored
with no glob before the folder, so it is now called literal, and the
docstring says so. A compose value is matched as written, since a
quoted one with spaces names another path. A case now fails without
the long-syntax bind branch, the !override constructor, or the clause
that keeps a tracked named file from counting twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The .lower() in the .txt test, the rstrip on the editor root, and the
normpath on a workspace root changed no result, since the name pattern
and secret_path_target already decide those cases. A case now fails
without ${pathSeparator}, the root .devcontainer.json pattern, the null
service guard, and a ? or [ glob before the folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 9e1bddccae55812462843d9524d66047f0cfa2f8, the content this pull request carries at that commit against develop, and it recorded 6 findings.

ptr727 and others added 2 commits November 2, 2026 16:48
SECRET_FOLDER already takes a leading ./ as a segment that normpath
drops, so SECRET_PATH's own optional ./ changed no result. A case now
fails without a floating line's fallback to its .gitignore's directory,
the mapping branch of the compose tag constructor, a comment on an
editor file's first line, and the strip of a padded .gitignore line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A floating line's prefix with no literal part is already its
.gitignore's directory, a compose name and an editor path never match
the same file, and an empty .gitignore line already names no secrets
folder, so each extra conditional is gone. A case now fails without
${containerWorkspaceFolder} and without the guard that reads no signal
file when no reader is given.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 266f99f60579405a45b23788778569de1034a9b1, the content this pull request carries at that commit against develop, and it recorded 1 finding.

@ptr727
ptr727 merged commit 436c79e into develop Nov 3, 2026
13 checks passed
@ptr727
ptr727 deleted the burndown/3719-bare-secrets branch November 3, 2026 01:20
ptr727 added a commit that referenced this pull request Nov 3, 2026
…f Filing Issues (#3846)

## Summary

Until now, filing an issue was always an acceptable way to dispose of a
finding. backlog-burndown's file claim and its prose bound ("the next
issue, filed") made filing the required route for a doc describing a
group's own change. This PR closes those routes. A fix that can land in
the pull request already open now lands there. Filing is kept for work
that really needs its own lane.

- **pr-review-conduct, outcome 4** (drive-pr carries it as an include):
  - An `introduced` finding is never filed.
- An edge case on new code is fixed where its deployment can produce the
input. Otherwise it is declined under Trust Boundaries.
- A `pre-existing` correctness defect in a file the diff touches is
fixed in this PR, within the same two-round budget. This uses the same
file grain as the class sweep, and Merge Gate item 3 excepts these
defects from the canonical tracker.
- Only a `pre-existing` correctness defect **in code that runs**,
elsewhere, is filed.
- An edge case on new code follows Trust Boundaries' whole
fix-or-decline test.
- The open-ended "Any other deferral is filed" catch-all is gone. The
only filings left are a design finding's untouched-file sites (one
issue, per "Triaging findings") and a fix belonging to another
repository.
- **GOVERNANCE.md, Verification Discipline** (agent-conduct carries it
as an include): the doc, manifest entry, or rule sentence describing
changed behavior is a sibling the change put in disagreement. It is
fixed in the change, not filed.
- **backlog-burndown**:
  - Claims predict the docs that describe each fix.
- A grown claim into an unclaimed file is granted at once. A grown claim
into a held file is sequenced: the requester's PR waits for the holder's
merge, and parks behind a holder that is stopped. A mutual wait is
adjudicated as a conflict. A file on an unclaimed branch stops for the
maintainer.
  - The prose bound admits units the change put in disagreement.
- Growth into carried canonical content or a design change under a
worker below `frontier` re-tiers the group, so that work never falls to
a lower tier.
- Hub workers read develop's copy of any skill develop has changed. This
closes the stale-installed-skill gap behind the self-written reports on
#3835, #3836, and #3838.
- **local-strict-review**: the reviewer brief stops asking for wording,
style, or consolidation remarks on text the diff did not write. Those
were dropped anyway, so this only cuts output and disposal tokens.

Maintainer decisions, 2026-11-02:
- Lever 1: agreed.
- Lever 2: file only code that runs.
- In-file pre-existing defects: fix them in the PR.
- Lever 3: rejected.

## Open `introduced` findings (loop stopped by the maintainer)

There were twelve recorded local passes at the `frontier` tier, raising
10, 9, 8, 6, 3, 3, 5, 4, 4, 2, 6, and 3 findings. Nearly every finding
was against text an earlier round had written. Of pass 11's six
findings, 1 to 5 were fixed in d70a96e. Finding 6, which asked to
revive the automatic re-tier, is declined: that hand-off drew new
findings in every round, so it was replaced on purpose with the existing
stop for the maintainer. By the maintainer's call, the last pass's
findings get no further edit round. On 2026-11-02 the maintainer
accepted both as known gaps (outcome 3):

1. `introduced`, backlog-burndown "Choosing the Worker's Model Tier":
the tier-stop paragraph's "claim comment is extended first" does not
repeat re-verify's limit to a file no branch holds. Read alone, it could
extend a claim over a file another group holds.
2. `introduced`, pr-review-conduct outcome 4, last bullet: where the
other repository's fix goes to the maintainer, no upstream issue exists
for the local blocker record to name.

## Pre-existing findings, not filed

- `pre-existing`, local-strict-review "The Carried-Content Sweep" with
pr-review-conduct outcome 4: a sweep pass's findings are on units the
sweep branch has not edited yet, so they route to the per-unit tracker
rather than to a fix.
- `pre-existing`, pr-review-conduct outcome 1 and "Triaging findings":
the untouched-file sites of a design finding are routed two ways. One
route files them as one issue, and the other drops them as a
consolidation on untouched text.

## Replay of the 25 issues the run filed

| Category | Issues | Under these rules |
| --- | --- | --- |
| Adjacent doc outside the claim | #3804, #3805, #3808, #3810, #3817,
#3820, #3837 | Fixed in the originating PR through the predicted or
granted claim. #3810 is a consolidation and #3817 is dead code, so each
is fixed if in a touched file and otherwise dropped or listed |
| Old defect next to the diff | #3813, #3821, #3824, #3825, #3833,
#3834, #3841, #3844 | Fixed where it sits in a touched file or unit.
Still filed only if it is code that runs elsewhere, which is about
#3821, #3824, and #3841. #3833 keeps its canonical tracker |
| Edge case past the done-definition | #3806, #3827, #3830, #3840, #3842
| `introduced`, so fixed in the PR or declined. #3830 is a contradiction
the fix wrote and is never filed |
| Decision | #3812, #3814, #3815, #3826 | Unchanged, still `decision`
issues |

Expected result for the same run: about 7 issues filed instead of 25.

Closes on promotion: #3845

## Verification

- `scripts/build_dist.py --check`: generated distributions are current.
- `prose_lint.py --diff origin/develop`: clean.
- `spec/validate.py`: OK.
- `repo_gate.py --check eol`: 0 issues.
- Docker markdownlint and cspell: 0 issues.
- local-strict-review: twelve passes recorded at the `frontier` tier.
The receipt covers the pushed head.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Nov 3, 2026
…rge on a Running Hosted Review, and Gate Skill Description Length (#3843)

Promotes the changes merged into `develop` since promotion #3797 to
`main`, the end of an away-mode backlog burndown.

- [#3803](#3803) exempts
the Roslyn embedded-language marker (`// lang=json`, `language=`) from
the prose gate's comment rules as a tool directive.
- [#3807](#3807) has
`local_review.py record` take `--report`, the file the reviewer wrote,
bind the pass to its sha256, and derive the finding count from it.
`status` gains `reportPath`.
- [#3809](#3809) holds
`pr_review.py merge` while a hosted review is still running on the head,
and routes a declined Qodo finding to a dismiss request.
- [#3811](#3811) dates an
anchored `intentRef` by the section its anchor names, and lets a
`driftNote` acknowledge a verified intent advisory.
- [#3816](#3816) moves the
null GraphQL node check into the shared `gh_graphql` transport as
`NullNodeError`.
- [#3818](#3818) explains
the workspace-edit default in `GOVERNANCE.md` and names the aggregator's
expression form.
- [#3822](#3822) moves the
abandon discard to the `backlog-burndown` orchestrator, aligns the
abandoned-branch delete, and holds a grown agent-safety set.
- [#3823](#3823) scopes
the Husky prose gate to staged paths and adds `--skip-generated` so a
named file inside a generated tree is skipped.
- [#3828](#3828) reads
Copilot's `Open findings:` label, drops the duplicate `null_node`, and
matches `scripts/README.md` to the Merge Gate.
- [#3829](#3829) bumps the
two stale hub caller snippet pins and documents the fallback's
mixed-pair refusal.
- [#3831](#3831) keeps an
inherited `GIT_DIR` from rerooting the prose gate's subdirectory git
reads.
- [#3832](#3832) gives
`backlog-burndown` a disposition for a worker's standalone clone and
keeps the agent-safety hold past a park.
- [#3835](#3835) makes
`carry.py check-sections` refuse what `apply-sections` would, and name
an open fence.
- [#3836](#3836) pins the
reusable-workflow stubs by placeholder and ticks the PlexCleaner gates
item.
- [#3838](#3838) has the
`runtime-secrets` audit dimension detect a bare `secrets/` directory
from the tracked files that name it.
- [#3839](#3839) gates
skill descriptions at the 1024-character limit and trims every one over
it.
- [#3846](#3846) fixes an
adjacent doc, an in-file pre-existing defect, and an edge case on new
code in the open pull request instead of filing an issue for each, and
keeps filing for code that runs elsewhere.
- [#3847](#3847) refuses
skill frontmatter that parses to a list or a scalar, so the description
length gate cannot be bypassed.

Fixes #3770
Fixes #3699
Fixes #3705
Fixes #3789
Fixes #1819
Fixes #727
Fixes #3710
Fixes #3706
Fixes #3623
Fixes #3687
Fixes #3617
Fixes #3757
Fixes #3790
Fixes #3786
Fixes #3785
Fixes #3772
Fixes #1657
Fixes #3443
Fixes #3824
Fixes #3817
Fixes #3805
Fixes #1666
Fixes #3700
Fixes #3821
Fixes #3771
Fixes #3794
Fixes #3825
Fixes #3690
Fixes #1472
Fixes #3813
Fixes #3719
Fixes #1592
Fixes #3845

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.

2 participants