Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions .gittensory.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,21 @@
# ----------------------------------------------------------------------------
# 1. FOCUS / GUARDRAILS (focus manifest)
# ----------------------------------------------------------------------------
# Declares the repo's work areas and off-limits paths. wantedPaths/blockedPaths feed advisory-only
# guidance findings; testExpectations/linkedIssuePolicy feed manifest_missing_tests and
# manifest_linked_issue_required, which — when `gate.manifestPolicy: block` is set below — can become
# enforceable blockers. Hard path HOLDS are a separate mechanism: settings.hardGuardrailGlobs, below.
# Declares the repo's work areas. wantedPaths feeds advisory-only guidance findings;
# testExpectations/linkedIssuePolicy feed manifest_missing_tests and manifest_linked_issue_required,
# which — when `gate.manifestPolicy: block` is set below — can become enforceable blockers. Hard path
# HOLDS are a separate mechanism: settings.hardGuardrailGlobs, below.

# Work areas the maintainer wants. PRs touching these are preferred/encouraged.
# Glob list. Default: [] (no preference).
wantedPaths:
- "src/**"

# Paths off-limits to contributors — CONTRIBUTOR-FACING GUIDANCE ONLY. Touching one surfaces in
# onboarding guidance and gittensory's own risk-reason commentary; it never blocks, holds, or produces
# a gate finding, even under gate.manifestPolicy: block. The only mechanism that actually holds a PR
# for a touched path is settings.hardGuardrailGlobs, below.
# Glob list. Default: [] (nothing listed).
blockedPaths:
- "vendor/**"
- ".github/workflows/**"
# blockedPaths is LEGACY and fully retired (#2974, 2026-07-04): the FocusManifest parser no longer
# reads this key at all, it produces zero findings, and it is not enforceable under any
# gate.manifestPolicy mode. A key left over from an older config has no runtime effect other than a
# migration warning from `npm run selfhost:config-lint`. Use settings.hardGuardrailGlobs below for
# real, enforceable path-based holds.

# Labels the maintainer prefers on incoming PRs; a missing preferred label is
# surfaced (never blocks). String list. Default: [].
Expand Down Expand Up @@ -269,8 +266,8 @@ gate:
mergeReadiness: off

# Manifest-policy gate. When `block`, this repo's declared policy from
# section 1 (blockedPaths, required linked issue, testExpectations) becomes
# an enforceable blocker. Independent of mergeReadiness.
# section 1 (required linked issue, testExpectations) becomes an
# enforceable blocker. Independent of mergeReadiness.
# off | advisory | block. Default: off.
manifestPolicy: off

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,15 +605,13 @@ features:
</p>
<p>
<code>blockedPaths</code> (top-level, alongside <code>wantedPaths</code>) is{" "}
<strong>contributor-facing guidance only</strong> — it never blocks, holds, or produces a
gate finding. A touched path surfaces in contributor onboarding guidance and in
gittensory&apos;s own risk-reason commentary, but the gate itself never enforces it.{" "}
<strong>fully retired</strong> (#2974) — the FocusManifest parser no longer reads this key
at all, it produces zero findings, and it is not enforceable under any{" "}
<code>gate.manifestPolicy</code> mode. Setting it in a config produces only a migration
warning from <code>npm run selfhost:config-lint</code>, nothing else.{" "}
<strong>The only mechanism that actually holds a PR for a touched path</strong> is{" "}
<code>settings.hardGuardrailGlobs</code> (config-as-code only, described above) — a
would-merge PR that touches a configured guardrail glob is held for manual review regardless
of <code>blockedPaths</code>. A legacy top-level <code>blockedPaths</code> that once acted
as an enforcement mechanism is retired; setting it produces a migration warning pointing at{" "}
<code>settings.hardGuardrailGlobs</code>. Default <code>[]</code> (nothing listed).
would-merge PR that touches a configured guardrail glob is held for manual review.
</p>

<h3>settings anti-abuse block</h3>
Expand Down
25 changes: 11 additions & 14 deletions config/examples/gittensory.full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,21 @@
# ----------------------------------------------------------------------------
# 1. FOCUS / GUARDRAILS (focus manifest)
# ----------------------------------------------------------------------------
# Declares the repo's work areas and off-limits paths. wantedPaths/blockedPaths feed advisory-only
# guidance findings; testExpectations/linkedIssuePolicy feed manifest_missing_tests and
# manifest_linked_issue_required, which — when `gate.manifestPolicy: block` is set below — can become
# enforceable blockers. Hard path HOLDS are a separate mechanism: settings.hardGuardrailGlobs, below.
# Declares the repo's work areas. wantedPaths feeds advisory-only guidance findings;
# testExpectations/linkedIssuePolicy feed manifest_missing_tests and manifest_linked_issue_required,
# which — when `gate.manifestPolicy: block` is set below — can become enforceable blockers. Hard path
# HOLDS are a separate mechanism: settings.hardGuardrailGlobs, below.

# Work areas the maintainer wants. PRs touching these are preferred/encouraged.
# Glob list. Default: [] (no preference).
wantedPaths:
- "src/**"

# Paths off-limits to contributors — CONTRIBUTOR-FACING GUIDANCE ONLY. Touching one surfaces in
# onboarding guidance and gittensory's own risk-reason commentary; it never blocks, holds, or produces
# a gate finding, even under gate.manifestPolicy: block. The only mechanism that actually holds a PR
# for a touched path is settings.hardGuardrailGlobs, below.
# Glob list. Default: [] (nothing listed).
blockedPaths:
- "vendor/**"
- ".github/workflows/**"
# blockedPaths is LEGACY and fully retired (#2974, 2026-07-04): the FocusManifest parser no longer
# reads this key at all, it produces zero findings, and it is not enforceable under any
# gate.manifestPolicy mode. A key left over from an older config has no runtime effect other than a
# migration warning from `npm run selfhost:config-lint`. Use settings.hardGuardrailGlobs below for
# real, enforceable path-based holds.

# Labels the maintainer prefers on incoming PRs; a missing preferred label is
# surfaced (never blocks). String list. Default: [].
Expand Down Expand Up @@ -283,8 +280,8 @@ gate:
mergeReadiness: off

# Manifest-policy gate. When `block`, this repo's declared policy from
# section 1 (blockedPaths, required linked issue, testExpectations) becomes
# an enforceable blocker. Independent of mergeReadiness.
# section 1 (required linked issue, testExpectations) becomes an
# enforceable blocker. Independent of mergeReadiness.
# off | advisory | block. Default: off.
manifestPolicy: off

Expand Down
1 change: 0 additions & 1 deletion src/queue/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7317,7 +7317,6 @@ async function maybeApplyManifestPolicyGate(
hasNoIssueRationale: hasClearNoIssueRationale(args.pr),
});
const policyCodes = new Set([
"manifest_blocked_path",
"manifest_linked_issue_required",
"manifest_missing_tests",
]);
Expand Down
13 changes: 13 additions & 0 deletions test/unit/config-templates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
resolveReviewPromptOverrides,
reviewConfigToJson,
} from "../../src/signals/focus-manifest";
import { lintManifestText } from "../../src/selfhost/config-lint";

// #1682: self-host operators need discoverable, copy-paste templates under config/examples/ that
// parse cleanly, stay in sync with the canonical root files, and keep the minimal starter safe.
Expand Down Expand Up @@ -51,6 +52,18 @@ describe("config/examples review templates (#1682)", () => {
expect(manifest.features.rag).toBeNull();
});

// #5294 (drift-audit roadmap #5270): parseFocusManifestContent above is the LENIENT parser (never
// warns on an unrecognized/retired top-level field by design) -- it structurally cannot catch a
// retired field like the old `blockedPaths` example creeping back into these shipped templates.
// lintManifestText is the ONLY function with the retired-field check (config-lint.ts's
// RETIRED_FIELD_MIGRATION_WARNINGS); assert it separately so a retired field reintroduced here fails
// CI instead of only being caught by eye.
it("lints gittensory.full.yml with zero warnings, including no retired top-level fields", () => {
const result = lintManifestText(readConfigExample("gittensory.full.yml"));
expect(result.warnings).toEqual([]);
expect(result.ok).toBe(true);
});

it("documents every shipped review.auto_review eligibility knob in gittensory.full.yml (#2055)", () => {
const full = readConfigExample("gittensory.full.yml");
for (const field of ["skip_labels", "skip_docs_only", "max_added_lines", "max_files"]) {
Expand Down
7 changes: 4 additions & 3 deletions test/unit/queue-2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3524,9 +3524,10 @@ describe("queue processors", () => {
});

// #4607 (maybeApplyManifestPolicyGate extraction): buildFocusManifestGuidance can produce findings whose
// code is NOT one of the three enforceable manifest-policy codes (manifest_blocked_path /
// manifest_linked_issue_required / manifest_missing_tests) -- e.g. manifest_off_focus, when wantedPaths is
// configured and no changed path matches it. Those non-enforceable findings must be filtered out before
// code is NOT one of the two enforceable manifest-policy codes (manifest_linked_issue_required /
// manifest_missing_tests -- manifest_blocked_path was retired #2974/removed from this Set #5294) -- e.g.
// manifest_off_focus, when wantedPaths is configured and no changed path matches it. Those non-enforceable
// findings must be filtered out before
// ever reaching the advisory/gate, never published alongside an enforceable one from the same pass.
it("filters out a non-enforceable manifest finding (manifest_off_focus) while still surfacing an enforceable one", async () => {
const env = createTestEnv({ GITHUB_APP_PRIVATE_KEY: await generatePrivateKeyPem() });
Expand Down
Loading