Skip to content

docs: document act-as-daemonset mode (OP-345) - #2748

Open
kristina-solovyova wants to merge 1 commit into
08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_from
08-17-docs_document_act-as-daemonset_mode_op-345_
Open

docs: document act-as-daemonset mode (OP-345)#2748
kristina-solovyova wants to merge 1 commit into
08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_from
08-17-docs_document_act-as-daemonset_mode_op-345_

Conversation

@kristina-solovyova

Copy link
Copy Markdown
Collaborator

doc/operator/deployment/act-as-daemonset.md covers how the mode is selected, what
gets auto-calculated, why compute hugepages are the practical ceiling, heterogeneous
fleets, the allowed sizing-mode transitions, expand-only reconciliation, the upgrade
effects on existing clusters, and the admission checks and events with their
troubleshooting.

cluster-capacity.md picks up the shared capacityPlannerConstraints knobs,
maxCoresPerContainer and the new unschedulable-container events. Also refreshes
drive-sharing.md, the summary.xml index, the generated api_dump, and the .ainav
navigation entries.

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

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

kristina-solovyova commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more


How to use the Graphite Merge Queue

Add the label main-merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has required the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude

claude Bot commented Aug 17, 2026

Copy link
Copy Markdown

Claude finished @kristina-solovyova's task in 6m 34s —— View job


Review: docs for act-as-daemonset mode

I treated this as a factual-accuracy review rather than a prose one, since the value of a doc like this is entirely in whether it matches the operator. I checked every number, formula, event, policy name, severity, default and transition rule against the source.

What checked out

Essentially all of it, including the parts that would have been easy to get wrong:

  • Every arithmetic chain in both worked examples reproduces exactly, integer truncation and round-up-to-even included. The 8-node fleet: 686,736 GiB703,217 MiB9,984/50,016109,070 at 8 containers → 89,666 at one core → 49,652 at 18 vs 51,950 at 17. And in cluster-capacity.md: 42,042 / 84,082 / 105,104, plus the 455,111 → 56,889 → 12 → t=96 (aggregate floor 89) chain and the 14-container t=98 variant. The hugepages.go comment says the doc "must agree number for number" — it does.
  • Formulas match hugepages.go:39-44 and :87-109: 1400×cores + 200×drives + 64×cores, and max(capacityBased + 1700×cores, 3000×cores) → even → cap → +DPDK. The cap-before-DPDK ordering is right.
  • All 10 event rows — type, throttle window, and per-node vs per-reason keying — match plannerEventSpecs in planner_events.go exactly. CapacityGrowthApplied really is a Warning on both growth kinds (steps_planner_apply.go:310, :452).
  • All 5 policy severities match internal/admission/defaults.go, cluster_sizing_mode_flip included at {Error, Error}.
  • The two allowed transitions match modeSwitchSupported, and the "rejected in both directions" rows are right.
  • Every Helm key, env var and default verified: maxCoresPerContainer: 19, the three ratios (2.0/1.0/0.0), hugepagesTlcRatio: 1000, hugepagesQlcRatio: 6000, computeMaxHugepagesMiB: 360000, tlcCapacityPerCoreGiB: 5120, form-cluster floor 5 / 3 under ALLOW_SINGLE_PARITY, DPDK 64. Dropping the maxComputeCoresPerNode row is correct — it's gone from the code.
  • Smaller claims too: protocol-role cores genuinely aren't checked; maxCoresPerContainer: 0 disables the policy; the infeasibility message really does name 10 nodes then (+N more); node fit really is computed against DriveContainerHugepagesMiB rather than a driveHugepages override, so the "escape hatch" warning is accurate.

Findings

# Where Severity
1 doc/summary.xml:31 — the index summary contradicts the doc in five places Main
2 act-as-daemonset.md:465 — best-effort caveat omits the foreign-pod blind spot Worth fixing
3 act-as-daemonset.md:938 — garbled "every mode change but two" sentence Minor
4 act-as-daemonset.md:185driveCores leg is skipped under a numDrives pin Minor
5 act-as-daemonset.md:376 — "one core each" hypothetical conflicts with remedy 6 Nit

#1 is the one that matters. summary.xml is what tooling reads instead of the 1029-line file, and two of its claims are the exact inverse of the doc: "drive-only growth is always free and needs no pod restart" (the doc: "cheap, but not free", and a restart is owed) and "existing containers gain drives while cores stay put" (the section title: "gain drives, and cores unless pinned"). It also quotes the retired 1664 MiB/drive core figure the doc exists to correct, says "four remedies" where there are six — dropping driveCores, the one lever that costs no capacity — and calls a 7-row table nine-row. Reads like it was written against an earlier draft and not re-synced.

#2 is a genuine gap rather than a wording issue. The doc's best-effort caveat blames only partial drive-signing, but the validator reads hugepages as allocatable and doesn't subtract foreign pods (cluster_auto_full_drives_compute_hugepages.go:51-54), whereas the runtime planner charges against every scheduled pod — which this same doc states under "Hugepages budget". So a busy-but-not-idle fleet is a second way to pass admission and still hit AutoFullDrivesInfeasible, and on a shared cluster it's likelier than the signing race.

Details, code references and suggested diffs are in the 5 inline comments.

One thing I could not verify

The verbatim CEL message quoted at act-as-daemonset.md:48-52, and the numDrives >= driveCores rule. Both live in pkg/weka-k8s-api, which is a replace target that isn't populated in this checkout. Code comments in cluster_num_drives_below_required_cores.go:18-20, templates.go:183 and cluster_auto_full_drives_pin_exceeds_node_drives.go:23 all corroborate that the rule exists and has the stated direction, so I have no reason to doubt it — I just didn't read the source. Worth a glance from someone with that module checked out, since the doc quotes the message verbatim and a drifted quote is invisible until a user compares it to their terminal.

Nothing here blocks; #1 is a two-minute fix and the rest are polish on a doc that is, on the evidence, unusually well checked against its implementation.
• branch 08-17-docs_document_act-as-daemonset_mode_op-345_

Comment thread doc/summary.xml
</file>
<file relpath="operator/deployment/act-as-daemonset.md">
<tags>act as daemonset, daemonset mode, auto full drives, AutoFullDrives, implicit sizing mode, mode detection, no flag, empty dynamicTemplate, both-or-neither, computeContainers driveContainers set together, CEL rejection, full drives, exclusive drives, per-node sizing, heterogeneous nodes, node-pinned drive container, drives decoupled from cores, numDrives override, numDrives pin, driveCores pin, drive core limit 19, maxCoresPerContainer, signed full drives, weka.io/weka-full-drives, hugepages budget, compute hugepages ceiling, hugepagesTlcRatio, computeMaxHugepagesMiB, capacity-based hugepages, compute sizing, computeToDriveCoreRatio, compute 1:1 floor, compute shortfall coverage, hard infeasibility, whole plan infeasible, one bad node blocks the cluster, RejectedNodes, mode flip rejection, one-way mode switch, changing sizing mode on a live cluster, adopting the daemonset mode, supported mode switches, cluster_auto_full_drives_pin_exceeds_node_drives, cluster_auto_full_drives_compute_hugepages, cluster_sizing_mode_flip, cluster_auto_full_drives_min_nodes, form-cluster minimum nodes, MinContainersNotReady, node selector sets container count, admission policy summary, AutoFullDrivesInfeasible, AutoFullDrivesDrivesStranded, AutoFullDrivesGrowthDetected, CapacityGrowthApplied, UnschedulableDriveContainer, UnschedulableComputeContainer, unschedulable planner container GC, AutoFullDrivesNodeIneligible, node eligibility, cordoned nodes, NotReady nodes, untolerated taints, driveHugepages override, computeHugepages override, FORM_CLUSTER_MIN_COMPUTE_CONTAINERS, drive cores never traded for compute, pod restart, expand-only reconciliation, drive-only growth is free, QLC drives excluded, QLCDrivesSkipped, upgrade note, nodeSelector scope</tags>
<summary>Deployment guide for the implicit "act as daemonset" sizing mode (internally auto full drives / AutoFullDrives): an exclusive full-drives mode selected by NOT setting container counts — active iff computeContainers, driveContainers, clusterCapacity, containerCapacity and driveCapacity are all unset — that creates one node-pinned drive container per eligible node and auto-derives numDrives, drive cores, hugepages and memory from that node's own signed full drives. There is no flag; an empty or absent dynamicTemplate is the mode. Covers the nine-row mode-detection decision table and the both-or-neither CEL rule rejecting exactly one of computeContainers/driveContainers (with the verbatim admission message); the comparison with explicit container counts and the drive-sharing modes; prerequisites (signing drives before cluster creation); the drives/cores decoupling — a container always takes ALL its node's signed drives (or the numDrives pin) while driveCores = pin else min(drives, 19), so numDrives == driveCores is NO LONGER an invariant, a driveCores pin below the drive count is lossless, and a pin above it is infeasible; numDrives as a per-node largest-drives override (above a node's signed count is infeasible, below strands the rest as an expected Normal event); the per-container 19-core limit capping cores only; the hugepages budget (1664 MiB/drive core, 3064 MiB/compute core floor); compute sizing from a configurable ratio (default 2:1 full-drives) with a hard 1:1 floor and how shortfalls are covered; the compute-hugepages ceiling as the practical limit — because all drives are claimed the capacity-based term is fixed and cannot be shrunk by capping cores — worked end to end on an 8-node lab fleet (8 x 6 x 14307 GiB = 686736 GiB claimed, 87902 MiB capacity share per container at 8 compute containers vs 50016 MiB free, needing 18 compute-eligible nodes) with four remedies (more compute nodes, raise hugepagesTlcRatio, lower computeMaxHugepagesMiB, pin numDrives lower) and admission enforcement; hard infeasibility when ANY node cannot fit a container sized for all its drives (nothing created anywhere, every offending node named with the binding dimension, and one bad node blocking the whole cluster called out); the one-way mode-switch rule on a live cluster enforced by cluster_sizing_mode_flip (Error in both modes, UPDATE-only, covering every sizing-mode pair since nothing else guards the capacity transitions) — explicit container counts to daemonset is ALLOWED, the running drive containers being adopted via the pod's node and grown in place to that node's full drive set with a pod recreation owed where cores rose, while daemonset to counts and every capacity transition except drive-sharing to clusterCapacity are rejected with reverting as the remedy; the note that all the other policies run on updates too, so the switch still faces the min-nodes, compute-hugepages and pin-exceeds gates; continuous expand-only reconciliation where drive-only growth is always free and needs no pod restart; the pod-restart caveat for core changes; the upgrade note that existing containers gain drives while cores stay put; QLC exclusion from full-drives signing; the full AutoFullDrives* event table with types and throttles, plus the container-level UnschedulableDriveContainer/UnschedulableComputeContainer reaps, gated on a confirmed PodScheduled=False/Unschedulable condition rather than age alone so a pod merely Pending during a slow drivers build is left alone; and troubleshooting for unsigned drives, stranded drives, fewer cores than drives, the two admission rejections, infeasibility, never-scheduled drive and compute containers (both reaped on the same terms, since an unscheduled compute container's cores are counted but never served — the reap requires a node-pinned container whose pod NEVER bound and a scheduler verdict standing longer than the timeout, timed from the verdict rather than from container creation), and nodes barred from NEW placement as cordoned, NotReady or carrying an untolerated taint (a Normal per-node AutoFullDrivesNodeIneligible event; existing containers there keep running, stay charged and still grow, and their unclaimed drives still count toward the plan's reported fleet total).</summary>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The summary contradicts the doc it indexes, in five places. summary.xml is what agents/tooling read instead of the 1029-line file, so a wrong claim here is worse than no claim — it lands the reader on the opposite conclusion from the one the doc works hard to establish.

  1. "the hugepages budget (1664 MiB/drive core, 3064 MiB/compute core floor)" — the doc's Hugepages budget exists specifically to retire the flat 1664/core figure: "it held only while drives and cores were locked together." hugepages.go:19-21 says the same. The summary asserts the very number the doc corrects.
  2. "with four remedies (more compute nodes, raise hugepagesTlcRatio, lower computeMaxHugepagesMiB, pin numDrives lower)" — the doc lists six, and the omitted [DEVOPS-1595] Install weka on underlying VM #4 is "Pin driveCores lower … the one remedy that costs no capacity at all". Dropping it loses the mode's headline lever. Add envtest  #6 (computeCores) is missing too.
  3. "drive-only growth is always free and needs no pod restart" — the doc says the opposite twice: "Drive-only growth is cheap, but not free" (200 MiB/drive), and the restart is owed because "the pod's hugepages limit is immutable and enforced". Confirmed in steps_planner_apply.go:324-336 — the AFD drives-only branch emits a Warning CapacityGrowthApplied, unlike the clusterCapacity branch which does say no restart required.
  4. "the upgrade note that existing containers gain drives while cores stay put" — the section is titled "existing clusters gain drives, and cores unless pinned", and its table shows a 3 → 6 core rise.
  5. "the nine-row mode-detection decision table" — it has 7 rows.

Points 3 and 4 look like they were written against an earlier draft and not re-synced.

Fix this →

Comment on lines +465 to +470
**Treat it as best-effort, not a guarantee.** The check projects from the drives signed **at the time
you apply**, and it skips nodes carrying no `weka.io/weka-full-drives` annotation yet — deliberately,
so that creating a cluster before any drives are signed is not blocked. The gap is the partial case: a
cluster applied while signing is still in progress is measured against only the nodes annotated so
far, so a claim that will not fit the finished fleet can pass admission and surface later as
`AutoFullDrivesInfeasible` at runtime. Sign the whole fleet before applying if you want admission to

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The best-effort caveat names only the partial-signing gap, but there's a second one that will bite more often on a shared fleet: the admission check reads node hugepages as allocatable, so foreign pods are not subtracted at all. From internal/validation/cluster_auto_full_drives_compute_hugepages.go:51-54:

"Node headroom is otherwise read as ALLOCATABLE hugepages-2Mi … so foreign pods are not subtracted. That over-states what is free on a busy node … this only fires when the requirement does not fit even an idle fleet."

The runtime planner, by contrast, charges against every scheduled non-terminal pod — which this doc states plainly under Hugepages budget ("a foreign workload's CPU/hugepages/memory requests reduce believed availability the same way a WekaContainer's do"). So the two models genuinely differ, and a fleet that is fine when idle but carries other workloads can pass admission and still land on AutoFullDrivesInfeasible. Given how careful the rest of the section is about which check owns what, worth one sentence here.

Suggested change
**Treat it as best-effort, not a guarantee.** The check projects from the drives signed **at the time
you apply**, and it skips nodes carrying no `weka.io/weka-full-drives` annotation yet — deliberately,
so that creating a cluster before any drives are signed is not blocked. The gap is the partial case: a
cluster applied while signing is still in progress is measured against only the nodes annotated so
far, so a claim that will not fit the finished fleet can pass admission and surface later as
`AutoFullDrivesInfeasible` at runtime. Sign the whole fleet before applying if you want admission to
**Treat it as best-effort, not a guarantee.** The check projects from the drives signed **at the time
you apply**, and it skips nodes carrying no `weka.io/weka-full-drives` annotation yet — deliberately,
so that creating a cluster before any drives are signed is not blocked. The gap is the partial case: a
cluster applied while signing is still in progress is measured against only the nodes annotated so
far, so a claim that will not fit the finished fleet can pass admission and surface later as
`AutoFullDrivesInfeasible` at runtime. Sign the whole fleet before applying if you want admission to
see the real number.
It also reads each node's hugepages as **allocatable**, without subtracting foreign pods — so it
measures an *idle* fleet, and only fires when the requirement does not fit even then. The runtime
planner charges against every scheduled, non-terminal pod (see [Hugepages
budget](#hugepages-budget)), so a fleet that is busy rather than idle can clear admission and still
go infeasible on the first reconcile. Check `weka-capacity explore-nodes` for the figures the planner
will actually see.

Comment on lines +937 to +941
**An update to a live cluster is rejected as a mode flip.**
Expected for every mode change but two: adding `computeContainers`/`driveContainers` to a live
daemonset cluster, or setting or unsetting `clusterCapacity`/`containerCapacity`/`driveCapacity` in
any other combination, is rejected once drive containers exist. Revert the change. The two
transitions that should be **accepted** are unsetting *both* container counts to adopt the daemonset

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This sentence is garbled: it opens "Expected for every mode change but two:" and then, after the colon, lists the rejections rather than the two exceptions — which only arrive in the following sentence. First read, adding computeContainers/driveContainers to a live daemonset cluster parses as one of the two allowed switches, which is exactly backwards (modeSwitchSupported in internal/validation/cluster_sizing_mode_flip.go:118-131 allows only counts→daemonset and drive-sharing→clusterCapacity).

Suggested change
**An update to a live cluster is rejected as a mode flip.**
Expected for every mode change but two: adding `computeContainers`/`driveContainers` to a live
daemonset cluster, or setting or unsetting `clusterCapacity`/`containerCapacity`/`driveCapacity` in
any other combination, is rejected once drive containers exist. Revert the change. The two
transitions that should be **accepted** are unsetting *both* container counts to adopt the daemonset
Only two mode changes are supported once drive containers exist: unsetting *both* container counts to
adopt the daemonset mode, and moving a drive-sharing cluster to `clusterCapacity`. Everything else is
rejected — adding `computeContainers`/`driveContainers` to a live daemonset cluster, and setting or
unsetting `clusterCapacity`/`containerCapacity`/`driveCapacity` in any other combination. Revert the
change. If you made one of the two supported switches and it was *still* rejected, the policy is
misfiring and it is worth reporting. Note that unsetting only one count

Comment on lines +185 to +186
**warning** in relaxed. The same policy covers a `driveCores` pin above a node's effective drive
count; it deliberately stays silent on a pin *below* it, which is lossless.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor precision point, in a section that is otherwise scrupulous about which check owns what: the policy's driveCores leg is skipped entirely when numDrives is pinned, so it doesn't cover that combination. cluster_auto_full_drives_pin_exceeds_node_drives.go:108-110:

// Effective drive count is the pin when set, else everything the node signed. Skipped
// entirely under a numDrives pin — CEL owns the numDrives >= driveCores comparison.
if driveCores > 0 && numDrives <= 0 && driveCores > signed {

So with both pinned, driveCores > numDrives is caught by the CRD's CEL rule (which the doc already documents two paragraphs down) and driveCores > signed cannot occur independently, since CEL bounds it by numDrives ≤ signed. Suggest scoping the sentence:

Suggested change
**warning** in relaxed. The same policy covers a `driveCores` pin above a node's effective drive
count; it deliberately stays silent on a pin *below* it, which is lossless.
**warning** in relaxed. The same policy covers a `driveCores` pin above a node's signed drive count
when `numDrives` is unset — with `numDrives` pinned, the CRD's `numDrives >= driveCores` CEL rule
owns that comparison instead; it deliberately stays silent on a pin *below* it, which is lossless.

Comment on lines +376 to +379
5. **Smaller compute containers do not rescue it.** Even at one core each, the capacity-based term
alone gives `87,902 + 1,700 + 64 = 89,666` MiB — still above the node's *entire* 60,000 MiB, before
the drive container takes its share. The binding term is claimed capacity, not cores, which is why
there is nothing for the operator to trade: only the container **count** in the denominator moves

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit on the hypothetical: it holds the count at 8 while dropping cores to 1, but that pair isn't reachable — remedy 6 says a computeCores pin derives the count as ceil(requiredComputeCores / computeCores), so computeCores: 1 would demand 96 containers, at which point capacityBased is 703,217 / 96 ≈ 7,325 MiB and does fit. The point you're making (at a fixed count, cores are not what binds) is right and worth making — it just reads as a contradiction against remedy 6 for anyone who checks. One clause fixes it:

Suggested change
5. **Smaller compute containers do not rescue it.** Even at one core each, the capacity-based term
alone gives `87,902 + 1,700 + 64 = 89,666` MiB — still above the node's *entire* 60,000 MiB, before
the drive container takes its share. The binding term is claimed capacity, not cores, which is why
there is nothing for the operator to trade: only the container **count** in the denominator moves
5. **Smaller compute containers do not rescue it.** Hold the count at 8 and shrink the containers: even
at one core each, the capacity-based term alone gives `87,902 + 1,700 + 64 = 89,666` MiB — still above
the node's *entire* 60,000 MiB, before

@kristina-solovyova
kristina-solovyova force-pushed the 08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_ branch from b0c56ee to ac1d906 Compare August 17, 2026 12:50
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-docs_document_act-as-daemonset_mode_op-345_ branch from c932080 to 4b14958 Compare August 17, 2026 12:50
@claude

claude Bot commented Aug 17, 2026

Copy link
Copy Markdown

Claude finished @kristina-solovyova's task in 1m 57s —— View job


Re-review after synchronize: no content change

  • Checked what the synchronize event actually carried
  • Confirmed the doc tree is unchanged from my last review
  • Re-verified the code anchors still hold after the rebase
  • Confirmed the 5 open findings still apply

This push was a stack rebase, not a doc change. The single commit 4b14958d keeps its original authoredDate (10:09Z — before my review) and only its committedDate moved (11:50Z), which is what Graphite does when a downstack PR is updated. The base ac1d906d carries the same commit timestamp, i.e. the whole stack was replayed at once. Diff stat is identical: 15 files, +1324/-70.

I re-read the four flagged locations and they are verbatim unchanged:

  • doc/summary.xml:31 — still says nine-row, 1664 MiB/drive core, four remedies, drive-only growth is always free and needs no pod restart, and existing containers gain drives while cores stay put.
  • act-as-daemonset.md — the best-effort caveat still names only the partial-signing gap; the "Expected for every mode change but two:" sentence is still inverted; the driveCores-pin sentence still reads "above a node's effective drive count" unqualified; the "Even at one core each" hypothetical still holds count at 8.

I also re-checked that the rebase didn't move the ground under the doc: internal/capacityplanner/hugepages.go is unchanged — 1400/200 per drive core/drive, max(capacityBased + 1700×cores, 3000×cores) → round to even → cap → +DPDK, with the cap still applied before DPDK. So the arithmetic I verified line-by-line last round still reproduces.

Open findings (unchanged, all in the inline comments above)

# Where Severity Status
1 doc/summary.xml:31 — index summary contradicts the doc in five places Main open
2 act-as-daemonset.md:470 — best-effort caveat omits the foreign-pod blind spot Worth fixing open
3 act-as-daemonset.md:941 — garbled "every mode change but two" sentence Minor open
4 act-as-daemonset.md:186driveCores leg is skipped under a numDrives pin Minor open
5 act-as-daemonset.md:379 — "one core each" conflicts with remedy 6 Nit open

Nothing new to add — the suggested diffs in the 5 inline comments still apply cleanly. #1 remains the only one I'd call worth doing before merge, since summary.xml is what tooling reads instead of the 1029-line file and two of its claims are the inverse of the doc's. Still non-blocking. Also still unverified, as before: the verbatim CEL message at act-as-daemonset.md:48-52 and the numDrives >= driveCores rule live in pkg/weka-k8s-api, which isn't populated in this checkout.

Fix all five →

• branch 08-17-docs_document_act-as-daemonset_mode_op-345_

@kristina-solovyova
kristina-solovyova force-pushed the 08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_ branch from ac1d906 to 367a3a0 Compare August 17, 2026 14:14
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-docs_document_act-as-daemonset_mode_op-345_ branch from 4b14958 to 13adcac Compare August 17, 2026 14:14
@claude

claude Bot commented Aug 17, 2026

Copy link
Copy Markdown

Re-review after synchronize: no content change (2nd rebase)

  • Checked what the synchronize event carried
  • Verified the doc tree is byte-identical to my last review
  • Re-confirmed the code anchors survived the rebase
  • Exited early — no new findings

Another stack rebase, not a doc change. The commit is now 13adcac0 (was 4b14958d), but it keeps its original authoredDate14:09:10+04:00 = 10:09Z, still before my first review — and only its committedDate moved, to 18:12:25+04:00. The base 367a3a02 carries the identical commit timestamp, so the whole stack was replayed at once. Diff stat is unchanged: 15 files, +1324/−70, with every per-file count matching (act-as-daemonset.md +1029/−0, cluster-capacity.md +164/−50, summary.xml +8/−4).

I confirmed this at the blob level rather than by eye — the three files carrying open findings hash to exactly what my previous reviews were anchored to:

File Blob
doc/summary.xml 333a857e
doc/operator/deployment/act-as-daemonset.md c3df3571
doc/operator/deployment/cluster-capacity.md 2bcd089c

Same hashes ⇒ the flagged lines are unchanged; no need to re-read them.

I also re-checked that the replay didn't move the ground under the doc. internal/capacityplanner/hugepages.go still has DriveHugepagesPerCoreMiB = 1400, DriveHugepagesPerDriveMiB = 200, MemoryPerCoreMiB = 3000 and max(capacityBased+1700*cores, 3000*cores) at line 100 — so the arithmetic I verified line-by-line in the first round still reproduces. cluster_sizing_mode_flip.go, cluster_auto_full_drives_compute_hugepages.go and admission/defaults.go all resolve cleanly too, so the transition rules, the allocatable-hugepages caveat and the five policy severities still read as documented.

Open findings (unchanged, all in the inline comments above)

# Where Severity Status
1 doc/summary.xml:31 — index summary contradicts the doc in five places Main open
2 act-as-daemonset.md:470 — best-effort caveat omits the foreign-pod blind spot Worth fixing open
3 act-as-daemonset.md:941 — garbled "every mode change but two" sentence Minor open
4 act-as-daemonset.md:186driveCores leg is skipped under a numDrives pin Minor open
5 act-as-daemonset.md:379 — "one core each" conflicts with remedy 6 Nit open

Nothing new. The suggested diffs in the 5 inline comments still apply cleanly. #1 is the only one I'd do before merge — summary.xml is what tooling reads instead of the 1029-line file, and two of its claims are the inverse of the doc's. Still non-blocking. Also still unverified, as before: the verbatim CEL message at act-as-daemonset.md:48-52 and the numDrives >= driveCores rule live in pkg/weka-k8s-api, a replace target that isn't populated in this checkout.

Fix all five →


View job run • branch 08-17-docs_document_act-as-daemonset_mode_op-345_

@kristina-solovyova
kristina-solovyova force-pushed the 08-17-docs_document_act-as-daemonset_mode_op-345_ branch from 13adcac to a8f3d2a Compare August 17, 2026 14:28
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_ branch from 367a3a0 to 28c8b8e Compare August 17, 2026 14:28
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-docs_document_act-as-daemonset_mode_op-345_ branch from a8f3d2a to b9e4652 Compare August 18, 2026 10:28
@claude

claude Bot commented Aug 18, 2026

Copy link
Copy Markdown

Claude finished @kristina-solovyova's task in 1m 30s —— View job


Re-review after synchronize: no content change (3rd rebase)

  • Checked what the synchronize event carried
  • Verified the reviewed files are byte-identical to my last review
  • Re-confirmed the code anchors survived the rebase
  • Exited early — no new findings

Another stack replay, not a doc change. The commit is now b9e4652a (was 13adcac0), and it keeps its original authoredDate14:09:10+04:00 = 10:09Z on 08-17, still before my first review — with only committedDate moving, to 2026-08-18T14:28:33+04:00. Base is now 28c8b8e0.

The three files carrying open findings hash to exactly what my previous reviews were anchored to:

File Blob
doc/summary.xml 333a857e
doc/operator/deployment/act-as-daemonset.md c3df3571
doc/operator/deployment/cluster-capacity.md 2bcd089c

Same hashes ⇒ the flagged lines are unchanged; no need to re-read them. Per-file diff stats also match (act-as-daemonset.md +1029/−0, cluster-capacity.md +164/−50, summary.xml +8/−4).

One stat did move: the PR total is now +1283/−70, down from +1324/−70. Deletions are unchanged and no per-file count in the doc tree moved, so this is the base branch having absorbed ~41 lines of pure additions during the replay — not content dropped from this PR. I re-read the whole non-doc remainder of the diff (.ainav/*, CLAUDE.md, dev_doc/drives-sharing-support.md, doc/api_dump/*, cluster-provisioning.md, drive-sharing.md) to confirm: it is a subset of what I verified in round one, with nothing new.

I also re-checked that the replay didn't move the ground under the doc. internal/capacityplanner/hugepages.go still has DriveHugepagesPerCoreMiB = 1400, DriveHugepagesPerDriveMiB = 200, MemoryPerCoreMiB = 3000 and the max(capacityBased + 1700×cores, 3000×cores) → round to even → cap → +DPDK chain with the cap still before DPDK — so the arithmetic I verified line-by-line still reproduces. cluster_sizing_mode_flip.go, cluster_auto_full_drives_compute_hugepages.go and admission/defaults.go all resolve cleanly, so the transition rules, the allocatable-hugepages caveat and the five policy severities still read as documented.

Open findings (unchanged, all in the inline comments above)

# Where Severity Status
1 doc/summary.xml:31 — index summary contradicts the doc in five places Main open
2 act-as-daemonset.md:470 — best-effort caveat omits the foreign-pod blind spot Worth fixing open
3 act-as-daemonset.md:941 — garbled "every mode change but two" sentence Minor open
4 act-as-daemonset.md:186driveCores leg is skipped under a numDrives pin Minor open
5 act-as-daemonset.md:379 — "one core each" conflicts with remedy 6 Nit open

Nothing new. The suggested diffs in the 5 inline comments still apply cleanly. #1 is the only one I'd do before merge — summary.xml is what tooling reads instead of the 1029-line file, and two of its claims are the inverse of the doc's. Still non-blocking. Also still unverified, as before: the verbatim CEL message at act-as-daemonset.md:48-52 and the numDrives >= driveCores rule live in pkg/weka-k8s-api, a replace target that isn't populated in this checkout.

Fix all five →

--- • branch 08-17-docs_document_act-as-daemonset_mode_op-345_

@kristina-solovyova
kristina-solovyova force-pushed the 08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_ branch from 28c8b8e to 5694b4a Compare August 19, 2026 13:50
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-docs_document_act-as-daemonset_mode_op-345_ branch from b9e4652 to 18f869e Compare August 19, 2026 13:50
@claude

claude Bot commented Aug 19, 2026

Copy link
Copy Markdown

Claude finished @kristina-solovyova's task in 6m 57s —— View job


Re-review after synchronize — content did change this time

  • Checked what the synchronize event carried
  • Confirmed this is not just a rebase — the doc tree actually moved
  • Checked whether the five open findings were addressed
  • Re-verified the current content against the code (arithmetic, events, policies, transitions)
  • Reviewed the non-doc remainder of the diff
  • Posted findings

Unlike the previous three pushes, this one edited the docs. act-as-daemonset.md is now 1008 lines (was 1029), cluster-capacity.md is +164/−51 (was +164/−50), and all three previously-anchored blobs differ. So I re-verified rather than exiting early.

What the edit did

The theme is stripping historical framing — which is exactly the rule this PR adds to CLAUDE.md. Removed:

  • the ~9-line "That is a deliberate answer to two symmetrical failures. Before drives were decoupled from cores, this same fleet formed happily…" paragraph from the worked example;
  • "and is the genuinely new option" from the driveCores remedy;
  • "This is a deliberate trade and a change in behaviour … where previously it would have been skipped" from the One bad node blocks the whole cluster callout, now condensed to the rationale alone;
  • "Without this the abort was invisible on the cluster" from the AutoFullDrivesGrowthDeferred row;
  • "If you made one of those two switches and it was still rejected, the policy is misfiring" from Troubleshooting.

Also improved: the min-nodes failure modes are now scoped to "In relaxed mode, where the policy only warns" and put in the present tense, which is more accurate than the old "was completely silent" — in strict mode those failures can't occur, because the apply is rejected. The design rationale that came out of the worked example survives in condensed form in the One bad node callout, so nothing load-bearing was lost.

Re-verification: everything still reproduces

I re-checked the current text against the code rather than assuming round one still held:

  • Every number in both worked examples reproduces exactly, integer truncation and round-up-to-even included — 686,736 → 703,217 → 9,984/50,016 → 109,070 at 8 containers, 89,666 at one core, 49,652 at 18 vs 51,950 at 17 (via 41,365 + 10,200 → 51,566 + 384). 1400/200/64, the max(capacityBased + 1700×cores, 3000×cores) chain, and the cap-before-DPDK ordering all match hugepages.go:39-44 and :88-110. 1464 = 1400 + 64 is right, with the 200 MiB/drive correctly excluded.
  • All 13 event rows match — the 10 cluster reasons against plannerEventSpecs (planner_events.go:64-87), and the 3 container-scoped ones against their direct Recorder.Event calls. No reason is missing in either direction, and the 4 WarningKind values are all mapped.
  • All 5 policy severities match internal/admission/defaults.go, cluster_sizing_mode_flip at {Error, Error} and update-only via the Validator/UpdateValidator split. "Five policies apply to this mode" is right — cluster_compute_drive_cores_floor is correctly out of scope, excluded by IsPlannerManaged plus the count guard.
  • The two allowed transitions match modeSwitchSupported (cluster_sizing_mode_flip.go:120-136), and every "rejected, both directions" row falls through to false.
  • The reap conditions match GarbageCollectUnschedulablePlannerContainers: pod never bound, container node-pinned, and the timeout measured from cond.LastTransitionTime — the scheduler's verdict, not container creation.
  • Defaults all still hold: 19, 1000, 6000, 360000, 5120, 2.0/1.0/0.0, DPDK 64, form-cluster 5/3 under ALLOW_SINGLE_PARITY.

Findings

Two new, both outside the docs — in the part of the diff I passed over in round one:

# Where Severity
A CLAUDE.md:70-77 — adds a second copy of the "Comments should be short" rule Worth fixing
B .ainav/controllers/wekacluster.md:39 — file goes 1.5KB → 4.3KB, past this PR's own 3KB guideline Minor

A is the one I'd fix. The base branch already has a short form of that rule at lines 67-68; this PR appends an expanded form at 70-77, separated by the unrelated - Never swallow errors bullet. The intent was clearly to replace the short line. It matters because CLAUDE.md loads into every agent's context on every session — the duplicate is pure token cost, and the two copies already differ (only the long one covers "the process of writing the code"), so they will drift. Suggested diff is inline.

B: .ainav/controllers/wekacluster.md grew 1,544 → 4,263 bytes. The content is good; it just wants to be a sibling file, the way wekacluster-drive-planning.md and management-proxy.md already are. (.ainav/index.md also crossed the line, 3,186 → 3,594; config/index.md was already over at 4,265 → 5,006.)

The five earlier findings are all still open

I checked each location in the current file — three of the five paragraphs were touched by this push but none of the substance changed:

# Where (current line) Status
1 doc/summary.xml:31 — index summary contradicts the doc in five places open, untouched
2 act-as-daemonset.md:451 — best-effort caveat omits the foreign-pod blind spot open — no allocatable/foreign-pod sentence anywhere in the file
3 act-as-daemonset.md:918 — garbled "every mode change but two" sentence open — edited ("should be accepted""are accepted"), but the colon still introduces the rejections
4 act-as-daemonset.md:190driveCores leg is skipped under a numDrives pin open — code re-confirms it: line 112 of the policy gates that leg on numDrives <= 0
5 act-as-daemonset.md:371 — "one core each" hypothetical conflicts with remedy 6 open, untouched

#1 is still the only one I'd call worth doing before merge: summary.xml is what tooling reads instead of the 1029-line file, and two of its claims are the inverse of the doc's — including drive-only growth is always free and needs no pod restart, which the doc now states twice as costing 200 MiB/drive and owing a restart. Note the irony that this push carefully de-historicized the prose while the index entry still quotes the retired 1664 MiB/drive core figure the doc exists to correct.

One small inconsistency I'll flag without opening a finding: cluster-capacity.md names the new validators by their Go type (clusterCoresPerContainerLimit, clusterComputeDriveCoresFloor) while act-as-daemonset.md uses the policy IDs (cluster_cores_per_container_limit, …). The camelCase form is that file's pre-existing convention, but the snake_case ID is what a user actually needs to set severities in Helm values — worth converging now that the two docs cross-link.

Still unverified, as in every previous round: the CEL message quoted verbatim at act-as-daemonset.md:48-52 and the numDrives >= driveCores rule live in pkg/weka-k8s-api, a replace target not populated in this checkout.

Nothing here blocks. On the evidence of two independent verification passes, this doc is unusually well-checked against its implementation — every figure I could recompute, recomputed.

Fix all seven →

--- • branch 08-17-docs_document_act-as-daemonset_mode_op-345_

Comment thread CLAUDE.md
Comment on lines 70 to +77
- Never swallow errors unless explicitly asked for
- Comments should be short, explain what the code does and why it is the way it is — nothing else.
Do NOT write comments about:
- History or changelog ("an earlier revision did X", "previously this was Y",
"renamed from Z", "added in PR #123") — that belongs in git or Jira tasks, not the source
- The process of writing the code ("as requested", "TODO: I chose this because",
self-justification, apologies, notes addressed to a reviewer)
- Anything restating the line below it, or narrating obvious mechanics

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This leaves two copies of the same rule in ## Code Style. The base branch already carries a short form of it two bullets up (line 67-68):

- Comments should be short, explain what the code does and why it is the way it is — nothing else.
Do NOT write comments about: history or changelog, anything restating the line below it, or narrating obvious mechanics

The block added here restates that verbatim in its first line and then expands the "Do NOT" list. It also lands after the unrelated - Never swallow errors bullet, so the two copies aren't even adjacent — a reader hits the short rule, an unrelated rule, then the long rule.

This matters more than a normal duplicate because CLAUDE.md is loaded into every agent's context on every session: the duplication is pure token cost, and the two copies can now drift independently (they already differ — only the long one covers "the process of writing the code").

Looks like the intent was to replace the short line, not append beside it. Note that the expanded version is what the rest of this PR is written against — the doc edits in this push strip "previously / a change in behaviour / the genuinely new option" framing out of act-as-daemonset.md, which is exactly the new "History or changelog" bullet in action.

Suggested change
- Never swallow errors unless explicitly asked for
- Comments should be short, explain what the code does and why it is the way it is — nothing else.
Do NOT write comments about:
- History or changelog ("an earlier revision did X", "previously this was Y",
"renamed from Z", "added in PR #123") — that belongs in git or Jira tasks, not the source
- The process of writing the code ("as requested", "TODO: I chose this because",
self-justification, apologies, notes addressed to a reviewer)
- Anything restating the line below it, or narrating obvious mechanics
- Comments should be short, explain what the code does and why it is the way it is — nothing else.
Do NOT write comments about:
- History or changelog ("an earlier revision did X", "previously this was Y",
"renamed from Z", "added in PR #123") — that belongs in git or Jira tasks, not the source
- The process of writing the code ("as requested", "TODO: I chose this because",
self-justification, apologies, notes addressed to a reviewer)
- Anything restating the line below it, or narrating obvious mechanics
A reader who has never seen the diff should find every comment useful.

…and drop the now-redundant short form at lines 67-68, keeping - Never swallow errors where it is.

Fix this →

Comment on lines +39 to +72
## Drive-container sizing modes

Mode is derived from which `spec.dynamicTemplate` fields are set; `plannerSizingMode`
(`steps_planner_apply.go`) is the single detection site.

| Mode | Family | Planner | Notes |
|------|--------|---------|-------|
| explicit counts (`computeContainers`+`driveContainers`, +`numDrives`/`driveCores`) | exclusive | none (static template) | uniform shape, scheduler-placed |
| `numDrives`+`driveCapacity` | drive-sharing | none (cores derived in `allocator.getDriveCores`) | TLC-only |
| `containerCapacity` | drive-sharing | none (cores derived) | split by `driveTypesRatio` |
| `clusterCapacity` | drive-sharing | `PlanCapacity` | whole-cluster target, FD-aware, grows |
| **daemonset** (auto full drives) | exclusive | `PlanAutoFullDrives` | active iff counts + all 3 capacity fields unset (`UsesAutoFullDrives()`); 1 node-pinned container per node taking all its signed drives, expand-only |

CEL both-or-neither: with no capacity field, `computeContainers`/`driveContainers` must be both set or both unset.

Event reasons/severities/throttling: `planner_events.go` (`plannerEventSpecs` table).

Core sizing formulas: `internal/capacityplanner/{cores,hugepages}.go` — drive/compute core arithmetic
(`FullDriveCores`, `RequiredComputeCores`) and hugepages (`DriveContainerHugepagesMiB`,
`ComputeContainerHugepagesMiB`).

Explicit `dynamicTemplate` overrides (cores, hugepages) are enforced by admission validators, not
auto-calculation.

Validators (`internal/validation/`, severities in `internal/admission/defaults.go`):

- `cluster_auto_full_drives_pin_exceeds_node_drives` — pinned cores/drives exceed node's signed drives
- `cluster_auto_full_drives_compute_hugepages` — projected compute hugepages exceed node headroom
- `cluster_auto_full_drives_min_nodes` — role selector matches fewer nodes than min container counts
- `cluster_sizing_mode_flip` — derived mode changed (UPDATE only) while drive containers exist
- `cluster_compute_drive_cores_floor` / `cluster_drive_compute_core_ratio` — compute:drive core ratio floor/advisory
- `cluster_cores_per_container_limit` — pinned cores above `maxCoresPerContainer`

Docs: `doc/operator/deployment/act-as-daemonset.md`, `cluster-capacity.md`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This block pushes the file past the size budget stated in this PR's own CLAUDE.md:

Files should stay under 3KB. If a file grows too large, split into subdirectories.

.ainav/controllers/wekacluster.md goes 1,544 → 4,263 bytes — 2.8× the guideline, and the added section is ~2.4KB of it. (.ainav/index.md also crosses over, 3,186 → 3,594; .ainav/config/index.md was already over and grows 4,265 → 5,006.)

The content itself is good and the mode table is genuinely useful — the issue is only where it lives. The file already uses the extract-and-link pattern for exactly this situation (wekacluster-drive-planning.md, management-proxy.md), so the natural fix is a sibling:

| `steps_planner_apply.go` | Build/apply for both planner modes → [wekacluster-sizing-modes.md](wekacluster-sizing-modes.md) |

with the mode table, the CEL note, the formula pointers and the validator list moving into .ainav/controllers/wekacluster-sizing-modes.md. That keeps wekacluster.md near its original size and puts the detail one hop away, which is what the 3-hop navigation model in CLAUDE.md asks for.

Not blocking — but this is the file agents load first for wekacluster, so it's the one where the budget is worth holding.

Fix this →

@kristina-solovyova
kristina-solovyova force-pushed the 08-17-docs_document_act-as-daemonset_mode_op-345_ branch from 18f869e to c528458 Compare August 19, 2026 15:28
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_ branch from 5694b4a to 1e55292 Compare August 19, 2026 15:28
@claude

claude Bot commented Aug 19, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

@kristina-solovyova
kristina-solovyova marked this pull request as ready for review August 19, 2026 15:30
@kristina-solovyova
kristina-solovyova requested a review from a team as a code owner August 19, 2026 15:30
@graphite-app
graphite-app Bot requested review from assafgi and tigrawap August 19, 2026 15:30
@claude

claude Bot commented Aug 19, 2026

Copy link
Copy Markdown

Claude finished @kristina-solovyova's task in 1m 21s —— View job


Re-review on ready_for_review: no content change

  • Checked what this event carried
  • Verified the reviewed files are byte-identical to my last review
  • Confirmed the seven open findings still apply
  • Exited early — nothing new

This was a stack replay plus a ready_for_review flip, not a doc change. The commit is c528458f and it keeps its original authoredDate2026-08-17 14:09:10 +0400 = 10:09Z on 08-17 — with only committedDate moving, to 2026-08-19 19:24:57 +0400 (15:25Z). The base 1e55292f carries the identical commit timestamp, so the whole stack was replayed at once.

Diff stat is unchanged from my 13:50Z review: 15 files, +1261/−70, with every per-file count matching — act-as-daemonset.md +1008/−0, cluster-capacity.md +164/−51, summary.xml +8/−4, CLAUDE.md +8/−0, .ainav/controllers/wekacluster.md +39/−1.

I spot-checked the actual bytes rather than trusting the stat, and all seven flagged locations are verbatim unchanged:

  • doc/summary.xml:31 — still contains nine-row, 1664 MiB/drive core, four remedies, drive-only growth is always free and needs no pod restart, gain drives while cores stay put.
  • act-as-daemonset.md — the best-effort caveat still names only the partial-signing gap; "Expected for every mode change but two:" still introduces the rejections after the colon; the driveCores-pin sentence is still unscoped; "Even at one core each" still holds the count at 8 implicitly.
  • CLAUDE.md — the committed tree still carries both copies of the "Comments should be short" rule (short form at 67-68, expanded form at 70-77, split by - Never swallow errors).
  • .ainav/controllers/wekacluster.md is still 4,263 bytes and .ainav/index.md 3,594, both over the 3KB guideline this PR itself states.

Open findings (unchanged, all in the inline comments above)

# Where Severity Status
1 doc/summary.xml:31 — index summary contradicts the doc in five places Main open
A CLAUDE.md:70-77 — second copy of the "Comments should be short" rule Worth fixing open
2 act-as-daemonset.md:451 — best-effort caveat omits the foreign-pod blind spot Worth fixing open
3 act-as-daemonset.md:918 — garbled "every mode change but two" sentence Minor open
4 act-as-daemonset.md:190driveCores leg is skipped under a numDrives pin Minor open
B .ainav/controllers/wekacluster.md:39 — file at 4.3KB, past the 3KB guideline Minor open
5 act-as-daemonset.md:371 — "one core each" conflicts with remedy 6 Nit open

Nothing new to add; the suggested diffs in the inline comments still apply cleanly. #1 remains the only one I'd do before merge — summary.xml is what tooling reads instead of the 1008-line file, and two of its claims are the inverse of the doc's. Still non-blocking.

Also still unverified, as in every round: the CEL message quoted verbatim at act-as-daemonset.md:48-52 and the numDrives >= driveCores rule live in pkg/weka-k8s-api, a replace target not populated in this checkout.

One aside, not a finding: this CI checkout has an uncommitted working-tree edit to CLAUDE.md that deletes the 8 lines this PR adds — i.e. it resolves finding A in the opposite direction (dropping the expanded rule, keeping the short one). It is not part of the PR and I left it alone; flagging only in case it points at something in the runner setup.
• branch 08-17-docs_document_act-as-daemonset_mode_op-345_

@kristina-solovyova
kristina-solovyova force-pushed the 08-17-docs_document_act-as-daemonset_mode_op-345_ branch from c528458 to b6b214a Compare August 19, 2026 15:33
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_ branch from 1e55292 to c96a3a8 Compare August 19, 2026 15:33
@claude

claude Bot commented Aug 19, 2026

Copy link
Copy Markdown

Claude finished @kristina-solovyova's task in 3m 8s —— View job


Re-review after synchronize: docs unchanged, but the diff shape moved

  • Checked what the synchronize event carried
  • Confirmed the doc tree is unchanged from my last review
  • Explained the file-count / line-count drop (15 → 13 files)
  • Re-verified the code anchors, since the base did change in this replay
  • Confirmed the seven open findings still apply

The docs did not change; the stack was replayed. Commit is now b6b214a4, keeping its original authoredDate2026-08-17 14:09:10 +0400 = 10:09Z on 08-17 — with only committedDate moving to 2026-08-19 19:33:02 +0400. Base c96a3a8e carries the identical commit timestamp, so the whole stack was replayed at once. Every per-file count in the doc tree is byte-for-byte what I reviewed at 13:50Z: act-as-daemonset.md +1008/−0 (still 1008 lines), cluster-capacity.md +164/−51, summary.xml +8/−4, CLAUDE.md +8/−0, .ainav/controllers/wekacluster.md +39/−1.

The one thing that did move: doc/api_dump/ went downstack

The PR total dropped +1261/−70 → +1259/−68 and the file count 15 → 13. That is not content leaving this PR — git log -- doc/api_dump/ now resolves the api_dump regeneration to 603ec88c ("feat: support full-drive wekacluster acting as a daemonset and using all drives"), i.e. it moved into the downstack PR that adds the API fields it is generated from. That is the right home for it: a generated reference belongs with the types, not with the narrative doc. The upshot is that this PR's diff is now purely hand-written docs + .ainav + CLAUDE.md, which is cleaner to review.

Why I re-verified instead of exiting early

The replay was not inert on the code side: internal/capacityplanner/hugepages.go is now 94 lines and my previous anchors shifted (max(capacityBased + 1700×cores, 3000×cores) was at :100, now :83). Since the ground under the doc moved, I re-checked the load-bearing claims rather than trusting the earlier passes:

  • Hugepages arithmeticDriveHugepagesPerCoreMiB = 1400, DriveHugepagesPerDriveMiB = 200, MemoryPerCoreMiB = 3000, and the chain max(capacityBased + 1700×cores, 3000×cores) → round up to even → cap at ComputeMaxHugepagesMiBthen + DPDK×cores (hugepages.go:83-91). Cap still before DPDK, so every figure in both worked examples still reproduces.
  • All 10 cluster event rows match plannerEventSpecs (internal/controllers/wekacluster/planner_events.go:64-86) on type, window and key — GrowthDeferred/ComputeLayout/Warning Warning at 15 min, DrivesStranded Normal at 15 min, PlacementDeferred/NodeIneligible Normal at 15 min per node, Planned/Infeasible/NoSignedDrives/GrowthDetected at 1 min per reason.
  • All 5 policy severities match internal/admission/defaults.go, cluster_sizing_mode_flip still {Error, Error}.
  • The two allowed transitions still match modeSwitchSupported (cluster_sizing_mode_flip.go:120-136) — counts→daemonset and drive-sharing→clusterCapacity, everything else falling through to false.

One nice thing I hadn't noted before: planner_events.go:11-13 now states that its rows "mirror the Events tables in doc/operator/deployment/{act-as-daemonset,cluster-capacity}.md, and a table test keeps the two in step" — and TestPlannerEventSpecsCoverEveryReason (funcs_fd_planning_test.go:919) exists. The doc↔code coupling this PR documents is test-enforced in at least that direction, which is more than most docs of this size get.

Open findings (unchanged, all in the inline comments above)

# Where Severity Status
1 doc/summary.xml:31 — index summary contradicts the doc in five places Main open
A CLAUDE.md:68 + :71 — two copies of the "Comments should be short" rule Worth fixing open
2 act-as-daemonset.md:451 — best-effort caveat omits the foreign-pod blind spot Worth fixing open
3 act-as-daemonset.md:918 — garbled "every mode change but two" sentence Minor open
4 act-as-daemonset.md:186driveCores leg is skipped under a numDrives pin Minor open
B .ainav/controllers/wekacluster.md — 4,263 bytes, past the 3KB guideline Minor open
5 act-as-daemonset.md:371 — "one core each" conflicts with remedy 6 Nit open

I confirmed each against the committed tree, not from memory: all five phrases (nine-row, 1664 MiB/drive core, four remedies, drive-only growth is always free and needs no pod restart, gain drives while cores stay put) are still in summary.xml; git show HEAD:CLAUDE.md still has the rule at both line 68 and line 71; wekacluster.md is still 4,263 bytes and .ainav/index.md 3,594. Findings 2 and 4 are re-confirmed by the code itself — cluster_auto_full_drives_compute_hugepages.go:52 still says "so foreign pods are not subtracted", and cluster_auto_full_drives_pin_exceeds_node_drives.go:112 still gates the driveCores leg on numDrives <= 0.

#1 stays the only one I'd do before merge: summary.xml is what tooling reads instead of the 1008-line file, and two of its claims are the inverse of the doc's. Non-blocking.

Still unverified, as in every round: the CEL message quoted verbatim at act-as-daemonset.md:48-52 and the numDrives >= driveCores rule live in pkg/weka-k8s-api, a replace target not populated in this checkout.

Aside, not a finding, same as last round: this CI checkout carries an uncommitted working-tree edit to CLAUDE.md that deletes the 8 lines this PR adds — resolving finding A in the opposite direction. Not part of the PR; I left it alone.

Fix all seven →

--- • branch 08-17-docs_document_act-as-daemonset_mode_op-345_

@graphite-app

graphite-app Bot commented Aug 19, 2026

Copy link
Copy Markdown

Graphite Automations

"Add anton/matt/sergey/kristina as reviwers on operator PRs" took an action on this PR • (08/19/26)

2 reviewers were added to this PR based on Anton Bykov's automation.

doc/operator/deployment/act-as-daemonset.md covers how the mode is selected, what
gets auto-calculated, why compute hugepages are the practical ceiling, heterogeneous
fleets, the allowed sizing-mode transitions, expand-only reconciliation, the upgrade
effects on existing clusters, and the admission checks and events with their
troubleshooting.

cluster-capacity.md picks up the shared capacityPlannerConstraints knobs,
maxCoresPerContainer and the new unschedulable-container events. Also refreshes
drive-sharing.md, the summary.xml index, the generated api_dump, and the .ainav
navigation entries.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-feat_weka-capacity_dry-run_for_auto-full-drives_op-345_ branch from c9d54cd to ea7b646 Compare September 1, 2026 18:43
@kristina-solovyova
kristina-solovyova force-pushed the 08-17-docs_document_act-as-daemonset_mode_op-345_ branch from 8f3d30b to c168aa3 Compare September 1, 2026 18:43
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