Skip to content

docs: review the configuration surface, and record three consumer asks against the published contract - #272

Merged
sunib merged 6 commits into
mainfrom
docs-config-surface-review
Jul 27, 2026
Merged

docs: review the configuration surface, and record three consumer asks against the published contract#272
sunib merged 6 commits into
mainfrom
docs-config-surface-review

Conversation

@sunib

@sunib sunib commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Two documents of planning work, plus the factual fixes each one turned up while being written.

What is here

1. The configuration-surface reviewdocs/future/config-surface-for-a-structured-repository.md

spec.path is still one string, while the folder it names has acquired structure: a layout, render roots, read-only context, build directives, an inferred placement convention, and a support verdict. The engine computes all of it; the GitTarget API exposes one bit (GitPathAccepted). The document reviews configuration.md and architecture.md, then orders the work that would close that gap — mode: Observe, status.layout, placement.mode, and moving commitWindow off GitProvider.

The sharpest case it makes is C2: pointing a GitTarget at apps/podinfo rather than apps/podinfo/overlays/prod gives two render roots and an ambiguous base, so a kubectl scale in prod rewrites the base and changes test too. Both spellings report Ready=True; the degradation is a debug log line.

2. Three asks from our first downstream consumerdocs/design/analyzer-consumer-contract-asks.md

They link pkg/manifestanalyzer, exec manifest-analyzer --mode scan-repo --format json from a second tool that does not link us, and run the reverser as an image. All three asks are one complaint: a distinction our doc comments assert, carried by prose nothing tests. One of them shipped a wrong sentence to a real user because of it.

  • Permanence on RefusalReason. The code space was never two-valued: issuesToReasons sets Code from every IssueKind, so the live values are eighteen codes plus refused-structural, and most are fixable today by the person reading the screen. A folder refused for invalid-yaml was reported to its owner as "not supported yet". Carries our classification of all eighteen — the part no consumer can maintain — and isolates the three that need a product decision rather than a lookup.
  • Provenance of the JSON document. The report names no analyzer version, the CLI has no --version, and no binary ships. That is a third pin on one release, recorded nowhere.
  • ResourceIdentifier.Key() as a documented contract. Verified: it has no test at all. We can change the format today with every gate green.

Written for an implementing party — nothing in either document is implemented here.

Fixes included

Both reviews turned up documentation that was untrue, corrected in the commit that found it:

  • Cluster-scoped resources use the literal _cluster/, not cluster/ (identifier.go, placement.go).
  • The placement section linked one file twice under two stale design/manifest/… labels, one captioned as a different document.
  • The design-document list linked architecture.md to itself; it now points at the support contract.
  • LayoutKustomizeOverlay still said such folders are "refused today, with a forward-looking reason", four lines above the constant saying the scanner adopts them. That sentence is what the consumer's broken code was written from.

Validation

task lint, task test (77.7%, baseline 77.8%, within the 0.5% tolerance) and task test-e2e (69 passed, 0 failed, 22 skipped) all pass.

The first e2e run failed in BeforeSuite with Ran 0 of 91 — the local k3d cluster was wedged with agents NotReady for four days, unrelated to this diff. task clean-cluster and a re-run gave the result above.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Expanded guidance for analyzer consumer contracts, including refusal permanence/actor classification, analyzer version/provenance reporting, and exact resource identifier key formats (with golden test expectations).
    • Added a structured proposal for repository configuration improvements, including observe vs write modes, richer status layout projections, placement controls, and a multi-wave rollout plan.
    • Updated architecture and configuration references for current Git path conventions and canonical spec locations.
    • Clarified Kustomize overlay behavior, including editable overlay scope and “real fault” refusal handling.

sunib and others added 2 commits July 26, 2026 20:25
Record the review of docs/configuration.md and docs/architecture.md as a
future-work proposal, and fix the factual errors it turned up:

- cluster-scoped resources use the literal `_cluster/`, not `cluster/`
  (internal/types/identifier.go, internal/manifestanalyzer/placement.go)
- the placement section linked the same file twice under two stale
  `design/manifest/...` labels, one claiming to be a different document
- the type-followability link carried a stale label
- the design-document list linked architecture.md to itself; it now points
  at the support contract, which the list was missing

The proposal itself argues the engine learned a lot about a folder — layout,
render roots, read-only context, ambiguity, a support verdict — while the API
still exposes one bit of it, and orders the work that would close that gap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ract

Our first downstream consumer links pkg/manifestanalyzer, execs the CLI from a
second tool, and runs the reverser as an image — so it feels every seam in what
we publish. All three of its asks are one complaint: a distinction our doc
comments assert, carried by prose nothing tests, encoded downstream after it
went stale.

Written for an implementing party, with each claim checked against the tree:

- RefusalReason carries no permanence, and the code space was never two-valued —
  issuesToReasons sets Code from every IssueKind, so a folder refused for
  invalid-yaml was reported to its owner as "not supported yet". Includes our
  classification of all eighteen kinds, which no consumer can maintain, and
  isolates the three that need a decision rather than a lookup.
- The JSON report names no analyzer version, the CLI has no --version, and no
  binary ships — three pins on one release, none of them recorded.
- ResourceIdentifier.Key() is a cross-product identity contract with no test at
  all; its format can change today with every gate green.

Also fixes the stale comment the first ask blames: LayoutKustomizeOverlay still
said such folders were "refused today, with a forward-looking reason", four
lines above the constant saying the scanner adopts them. That sentence is what
the consumer's code was written from.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@sunib, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a085e956-1a04-4aa7-a917-2b305d1686b6

📥 Commits

Reviewing files that changed from the base of the PR and between 793f156 and 9cd1f43.

📒 Files selected for processing (1)
  • docs/design/analyzer-consumer-contract-asks.md
📝 Walkthrough

Walkthrough

The PR adds analyzer consumer-contract requirements, proposes structured repository configuration changes, updates documentation links and path conventions, and revises LayoutKustomizeOverlay documentation.

Changes

Documentation and contract clarification

Layer / File(s) Summary
Analyzer consumer contract asks
docs/design/analyzer-consumer-contract-asks.md, docs/INDEX.md
Defines refusal classification and actor metadata, analyzer provenance and versioning, ResourceIdentifier.Key() formatting, and testing expectations.
Structured repository configuration proposal
docs/future/config-surface-for-a-structured-repository.md, docs/INDEX.md
Proposes documentation restructuring, observe/write modes, layout status projection, placement inference controls, commit setting relocation, onboarding changes, and rollout waves.
Architecture and overlay documentation alignment
docs/architecture.md, docs/configuration.md, pkg/manifestanalyzer/repo.go
Updates cluster-scoped path conventions and documentation links, and describes accepted overlay render-root ownership and refusal-code semantics.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is relevant but does not follow the required template and omits Type of Change, Testing, Checklist, and Related Issues. Add the template sections with selected change type, testing results, checklist items, related issue links, screenshots if needed, and brief notes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main documentation updates and the downstream consumer-contract asks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs-config-surface-review

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

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/INDEX.md (1)

68-74: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the stale open-item count.

The table now contains thirteen open items, including the newly added analyzer-contract document, but the heading still says “Twelve other open items.” Update the count or remove the stale quantifier.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/INDEX.md` around lines 68 - 74, Update the open-item heading in
docs/INDEX.md to reflect the table’s thirteen entries, or remove the stale
numeric quantifier; leave the listed documents and descriptions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/design/analyzer-consumer-contract-asks.md`:
- Around line 234-243: Clarify the contract around ReportProvenance by
documenting the exact RepoReport and FolderReport JSON nesting and placement of
analyzerVersion. State that each report must include a non-empty
analyzerVersion, including a defined fallback for unreleased or unavailable
versions, and remove or revise omitempty so the field cannot be omitted.
- Around line 124-140: Reconcile the permanence inventory with the complete set
of emitted issue variants, including refused-structural and the special branches
unsupported-kustomize, unresolved-krm, and kustomize-render-refused. Update the
inventory and classification tests to enumerate every variant, then add
branch-level coverage for each per-construct emission path so any newly emitted
issue must have an explicit permanence classification.

In `@docs/future/config-surface-for-a-structured-repository.md`:
- Around line 334-346: Update the namespace-inference example around all.yaml so
it satisfies the documented cohort rule: show ConfigMaps from at least two
existing namespaces in all.yaml before describing a new billing ConfigMap being
appended there. Alternatively, revise the example’s expected destination to the
canonical layout; keep the explanation consistent with the chosen behavior.

---

Outside diff comments:
In `@docs/INDEX.md`:
- Around line 68-74: Update the open-item heading in docs/INDEX.md to reflect
the table’s thirteen entries, or remove the stale numeric quantifier; leave the
listed documents and descriptions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8f327355-a20a-4fc3-bacf-ab2c22818298

📥 Commits

Reviewing files that changed from the base of the PR and between ce2a5fd and bac9ab5.

📒 Files selected for processing (6)
  • docs/INDEX.md
  • docs/architecture.md
  • docs/configuration.md
  • docs/design/analyzer-consumer-contract-asks.md
  • docs/future/config-surface-for-a-structured-repository.md
  • pkg/manifestanalyzer/repo.go

Comment thread docs/design/analyzer-consumer-contract-asks.md
Comment thread docs/design/analyzer-consumer-contract-asks.md Outdated
Comment thread docs/future/config-surface-for-a-structured-repository.md Outdated
@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…nce example

Review findings from PR #272, all four verified against the tree before fixing:

- The kind count was wrong and hid a real gap. internal/manifestanalyzer defines
  seventeen IssueKinds, not eighteen, and pkg/manifestanalyzer re-declares only
  fourteen — so kustomize-render-refused, render-does-not-match-live and
  unplaceable-edit can reach a consumer through issuesToReasons with no exported
  constant to match on. Recorded as a second gap to close in the same pass.
- A per-constant classification test cannot reach the per-construct branches of
  unsupported-kustomize, unresolved-krm and kustomize-render-refused, which is
  the original bug one level down. The ask now requires per-emission-path
  coverage.
- analyzerVersion was specified as a nested, omitempty field, which contradicts
  the ask it serves: a report must always say what produced it. It is now a
  non-empty top-level string on both reports, with the fallback chain stated.
- The C3 inference example did not satisfy its own precondition. A cohort admits
  a never-seen namespace only once it holds more than one (configuration.md
  652-655), so a bundle of nine ConfigMaps in one namespace inverts the answer.
  The example now spans two namespaces, and its failure mode is the sharper one:
  the file is still there and still full of ConfigMaps.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
docs/design/analyzer-consumer-contract-asks.md (3)

313-315: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make the release platform matrix normative.

“Decision for the implementer” and “the obvious third” do not satisfy the requirement for an explicit platform matrix. Choose and document the required GOOS/GOARCH targets, including which binaries receive release attestations.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/design/analyzer-consumer-contract-asks.md` around lines 313 - 315,
Update the platform decision in the design document to explicitly define the
normative GOOS/GOARCH release matrix, replacing the tentative wording about
implementer choice and the “obvious third” platform. Specify which target
binaries are built and which receive release attestations.

125-131: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Define the exact serialized shape of Issue.

The text says Issue carries Permanence and Actor, but does not specify whether they are top-level fields, their JSON names, or their zero-value/omitempty behavior. Add the corresponding Issue struct shape and require tests for it, just as the document does for RefusalReason.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/design/analyzer-consumer-contract-asks.md` around lines 125 - 131,
Define the serialized Issue shape in the contract, explicitly showing top-level
Permanence and Actor fields, their exact JSON names, and zero-value/omitempty
behavior. Add tests covering serialization of these fields, including zero
values, matching the documented RefusalReason coverage.

286-297: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Resolve SchemaVersion semantics instead of leaving them as open questions.

This section asks the implementer to decide what a bump means and how readers handle unknown versions, but does not state the contract. Document which changes require a bump and whether unknown versions must be rejected or parsed best-effort; otherwise consumers will implement incompatible policies.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/design/analyzer-consumer-contract-asks.md` around lines 286 - 297,
Update the SchemaVersion section to define its contract explicitly: state which
schema changes require a version bump, clarify whether a bump covers field
removal, meaning changes, or both, and specify whether readers that know v1 must
reject v2 or parse it best-effort. Also explain what breaking changes remain
after additive fields are explicitly excluded from bumping.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/design/analyzer-consumer-contract-asks.md`:
- Around line 313-315: Update the platform decision in the design document to
explicitly define the normative GOOS/GOARCH release matrix, replacing the
tentative wording about implementer choice and the “obvious third” platform.
Specify which target binaries are built and which receive release attestations.
- Around line 125-131: Define the serialized Issue shape in the contract,
explicitly showing top-level Permanence and Actor fields, their exact JSON
names, and zero-value/omitempty behavior. Add tests covering serialization of
these fields, including zero values, matching the documented RefusalReason
coverage.
- Around line 286-297: Update the SchemaVersion section to define its contract
explicitly: state which schema changes require a version bump, clarify whether a
bump covers field removal, meaning changes, or both, and specify whether readers
that know v1 must reject v2 or parse it best-effort. Also explain what breaking
changes remain after additive fields are explicitly excluded from bumping.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: de6fe501-5ad1-4757-8244-7139a7168073

📥 Commits

Reviewing files that changed from the base of the PR and between bac9ab5 and 793f156.

📒 Files selected for processing (3)
  • docs/INDEX.md
  • docs/design/analyzer-consumer-contract-asks.md
  • docs/future/config-surface-for-a-structured-repository.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/INDEX.md

sunib and others added 3 commits July 27, 2026 04:15
apiVersion + kind replaces schemaVersion and dissolves the three open questions
about what a bump asserts: the Kubernetes API conventions already answer them,
in a document every consumer of a GitOps tool has read. The spec/status split
turns out to be honest here — spec is the scan request, status the observation —
which also gives today's floating "informational" root field a home.

Carved out: no metadata (a report has no identity, and the field invites an
apply that will never work — kpt's ResourceList sets the same precedent), and
never served or registered. Costs one breaking change to the JSON contract,
which argues for doing it inside Ask 2 while there is one consumer to coordinate
with. It does not replace Ask 2: apiVersion versions the contract,
analyzerVersion records the build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…r issues

A second team filed four issues against v0.39.1, verified by measurement rather
than by reading. Three of their asks were already covered; five points were not:

- The block a consumer reads first is the one that misleads. "Refusal reason
  codes a candidate may carry" lists two of eighteen, one retired, and nothing
  says RefusalReason.Code draws from IssueKind — a more direct cause of their
  wrong sentence than the Layout comment was. Type the field, fix the header.
- Their permanence enum has two values; ours keeps four. A two-valued enum drops
  the not-yet axis, which is the exact distinction that went degenerate.
- --version must print the SchemaVersion it emits, not only the release.
- Their generator{name,version} beats our flat analyzerVersion: a piped report
  needs to say which tool, not only which release.
- Key()'s golden test needs a fourth case, core cluster-scoped (/v1/nodes/node-1),
  where group and namespace are both empty and degenerate in opposite ways. All
  four shapes confirmed by running them.

The two teams disagree on one point — attestation versus checksums — so the doc
now says do both: the attestation is the stronger claim, the checksum is what a
Dockerfile can consume without a token.

Also records that the minimal-version-selection diamond is explicitly not our
bug, so nobody restructures the module to solve it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The KRM envelope is adopted rather than recommended: apiVersion/kind replaces
schemaVersion, spec carries the scan request and status the findings. Taken as a
deliberate breaking change now, while there are two consumers and both are asking
for version clarity in this same document. The provenance field settles as
status.generator{name,version} — the second team's shape, because a piped report
needs to say which tool and not only which release.

The three unclassified refusal codes are decided during implementation: the
session proposes a permanence per raise site and raises each as a review comment
for the maintainer to accept or overturn. They never ship as PermanenceUnknown,
and they no longer block the other fourteen.

Also folds the SchemaVersion section into the envelope decision that answers it,
rather than leaving three open questions beside their own answer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sunib
sunib merged commit 1f0b5d1 into main Jul 27, 2026
7 checks passed
@sunib
sunib deleted the docs-config-surface-review branch July 27, 2026 04:46
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.

1 participant