Skip to content

Commit 607eec1

Browse files
David-Noble-at-workDavid Noble
andauthored
docs(plans): re-audit the rename plan and write the name-mapping appendix (#718)
Closes #716. The plan sat at status draft since 2026-05-30, presenting 2026-05-26 measurements as current and claiming a prerequisite satisfied months ago. Every quantity in it was wrong, and it lacked the one artifact its own goal 4 promises. Current State re-audited against the tree Root .go files 62 -> 108, provider files 76 -> 238, qualified op.X references ~2,499 -> 3,880, generated files 29 -> 48. Every line reference had shifted, and Node has moved out of graph.go into node.go since the last audit. The subpackage list was wrong in both directions: sops/ has left, claimcheck/ and server/ arrived. The deltas are kept in "What moved between audits" rather than discarded -- the scale of drift is the argument for not letting a plan sit at draft. Subpackages dispositioned claimcheck/ is nearly rename-inert: it hardcodes only pkg/assert and pkg/fsroot as trust boundaries and loads the whole module by pattern, which the rename does not change. server/ uses op.ControlPlane, op.RunStatus, and the op.Control* family, NONE of which this rename touches. Both are Phase 5 concerns only. Additions since the audit checked for impact Method claims, the run-state machine, the control plane, sealed resources, and the conversion rules name claims, control, and conversion -- no graph-structure vocabulary, and none collides with a target name. The appendix, which the plan did not have Rename Mapping was five rows of top-level types. Goal 4 promises reviewers can verify by inspection; without a full mapping there was nothing to inspect against. The appendix covers the exported non-test surface: types, constructors, functions, methods whose own name changes, and hooks. It also carries two sections that only exist because a rename is not mechanical: KEEPS ITS NAME, verified by ABSENCE from the diff. A table of only the changes cannot distinguish "correctly unchanged" from "missed". DO NOT RENAME -- NOT OURS. pkg/op/default_eval.go reads tree.Root.Nodes[0].(*parse.ActionNode). Those are text/template/parse types, and .Nodes is a field on a STDLIB type. A word-level sweep over Node rewrites it and fails to compile. Writing it caught an error already in the plan Phase 1's target list said `GenerateNodeID -> GenerateStepID, NodeID -> StepID`. That is wrong. flow/helpers.go calls GenerateNodeID(string(Subgraph)), so it mints ids for composites as well as leaves -- it names the ABSTRACT VERTEX, which under the new taxonomy is Node, the name it already has. Following the plan as written would have produced GenerateStepID minting ids for Blocks. Phase 1 and the appendix both corrected. Open questions settled where they could be Q2 restated: sops/ is gone, claimcheck/ and server/ arrived, and the starlarkbridge edit ban has been lifted, so all five subpackages are edit-eligible on the same terms. Q3 answered: epic #451, with #716 and #715 beneath it. Q4 left open: TEMPLATE.md gained a Test Plan section on 2026-08-27 and this plan has none -- for a pure rename the assertion is "every existing test passes unchanged", which Verification already states. Confirm rather than duplicate. Q5 added: the Documentation Audit predates 3.2, 3.6, 4.5, and the provider catalog, all of which now describe pkg/op in prose a pure rename churns. In scope, or a follow-up? Status draft -> ready. Phase sequencing re-verified: NodeSpec (node.go:473) and ExecutableUnitSpec (executable_unit.go:425) both exist, so Phase 1 must still free the name before Phase 2 claims it. Co-authored-by: David Noble <[email protected]>
1 parent 12cde36 commit 607eec1

1 file changed

Lines changed: 197 additions & 67 deletions

File tree

‎docs/plans/workflow-rename.md‎

Lines changed: 197 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
---
22
title: "Rename op → workflow with Definition/Node/Block/Step taxonomy"
3-
issue: TBD
4-
status: draft
3+
issue: 451
4+
status: ready
55
created: 2026-05-26
6-
updated: 2026-05-30
6+
updated: 2026-08-27
77
---
88

99
# Plan: Rename op → workflow
1010

11-
> **Read this first.** The prerequisite below is **satisfied** — `refactor/extract-starlark-from-op.phase-8`
12-
> merged long ago — but the plan has not been revisited since **2026-05-26**, and every quantity in its
13-
> Current State is now wrong. See §Staleness. Two issues carry the work to fix that:
11+
> **Re-audited 2026-08-27** under [#716](https://github.com/NobleFactor/devlore-cli/issues/716). The original
12+
> prerequisite is satisfied, the Current State reflects the tree, and §Appendix: Name Mapping now gives a
13+
> reviewer something to inspect a diff against — which goal 4 promises and the plan previously lacked.
1414
>
15-
> - [#716](https://github.com/NobleFactor/devlore-cli/issues/716) — re-audit, and write the name-mapping
16-
> appendix this plan lacks
17-
> - [#715](https://github.com/NobleFactor/devlore-cli/issues/715) — rename the provider roles, which belongs
18-
> in the same window; #716 blocks it
15+
> Writing the appendix caught an error already in the plan: Phase 1 listed
16+
> `GenerateNodeID → GenerateStepID`, which is wrong. See §Appendix.
1917
>
20-
> Do not start a phase from the numbers below.
18+
> [#715](https://github.com/NobleFactor/devlore-cli/issues/715) renames the provider roles and belongs in the
19+
> same window; see §Related Rename.
2120
2221
## Summary
2322

@@ -42,32 +41,58 @@ The real prerequisite now is [#716](https://github.com/NobleFactor/devlore-cli/i
4241
facts are three months stale, and a phase started from them would be scoped against a package 74% smaller than
4342
the one that exists.
4443

45-
## Current State (audited 2026-05-26)
44+
## Current State (audited 2026-08-27)
4645

4746
| Element | Current | Location | Notes |
4847
|---|---|---|---|
49-
| Package | `pkg/op/` | — | 62 .go files at root |
50-
| Subpackages | `provider/`, `starlarkbridge/`, `inventory/`, `sops/` | — | 76, 5, 2+1.gen.go, 13 files |
51-
| Abstract vertex | `ExecutableUnit` (interface) | `executable_unit.go:29` | → `Node` |
52-
| Leaf variant | `Node` (struct) | `graph.go:380` | has `Layer` + `Origin` fields → `Step` |
53-
| Composite variant | `Subgraph` (struct) | `subgraph.go:28` | contains `Children []SubgraphChild` → `Block` |
54-
| Durable record | `RecoveryStack` (struct) | `recovery_stack.go:16` | → `Ledger` |
55-
| Recovery anchor | `RecoverySite` (struct) | `recovery_site.go:32` | name stays — see Out of Scope |
56-
| Container | `Graph` (struct) | `graph.go:40` | → `Definition` |
57-
| Runtime driver | `GraphExecutor` (struct) | `graph_executor.go:32` | → `Executor` |
58-
| Connection | `Edge` (struct) | `graph.go:368` | planning-time |
59-
| Slot binding | `Binding` (interface) | `binding.go:15` | variants `ImmediateBinding` / `PromiseBinding` / `VariableBinding`; no concrete `Slot` type exists |
60-
| Durable entry | `Receipt` (interface) | `receipt.go:20` | |
61-
| Importing files outside `pkg/op/` | ~200 | spans `cmd/`, `internal/` | |
62-
| Qualified `op.X` references | ~2,499 | non-test + test combined | |
63-
| Generated files in scope | 29 `.gen.go` | `pkg/op/provider/*/gen/` + `pkg/op/inventory/` | regenerate via `make build` |
64-
| Name collisions for new names | `Step` (cross-package only) | repo-wide | `Block`, `Ledger`, `Workflow`, `Definition`, `Executor` are all unused elsewhere. `Step` has no language-level clash: the only existing type is `console.Step` in `internal/console` (a TUI session step, different package); the `pkg/op` "Step" hits are comment prose ("Step 3 fires…"), not identifiers. |
65-
66-
### Staleness (measured 2026-08-27)
67-
68-
Every quantity above is wrong. [#716](https://github.com/NobleFactor/devlore-cli/issues/716) re-audits it.
69-
70-
| Element | Audited 2026-05-26 | Measured 2026-08-27 | |
48+
| Package | `pkg/op/` | — | 108 .go files at root |
49+
| Subpackages | `claimcheck/`, `inventory/`, `provider/`, `server/`, `starlarkbridge/` | — | 3, 3, 238, 3, 8 files |
50+
| Abstract vertex | `ExecutableUnit` (interface) | `executable_unit.go:39` | → `Node` |
51+
| Leaf variant | `Node` (struct) | `node.go:19` | moved out of `graph.go` since the last audit → `Step` |
52+
| Composite variant | `Subgraph` (struct) | `subgraph.go:32` | → `Block` |
53+
| Durable record | `RecoveryStack` (struct) | `recovery_stack.go:37` | → `Ledger` |
54+
| Recovery anchor | `RecoverySite` (struct) | `recovery_site.go:33` | name stays — see Out of Scope |
55+
| Container | `Graph` (struct) | `graph.go:50` | → `Definition` |
56+
| Runtime driver | `GraphExecutor` (struct) | `graph_executor.go:44` | → `Executor` |
57+
| Connection | `Edge` (struct) | `graph.go:1079` | planning-time; name stays |
58+
| Slot binding | `Binding` (interface) | `binding.go:21` | 3 variants; name stays |
59+
| Durable entry | `Receipt` (interface) | `receipt.go:22` | name stays |
60+
| Serialized forms | `graphData`, `nodeData`, `subgraphData` | `graph.go`, `node.go` | follow their subjects |
61+
| Files importing `pkg/op` outside it | 130 | spans `cmd/`, `internal/`, `pkg/` | |
62+
| Qualified `op.X` references | 3,880 | non-test + test combined | |
63+
| Generated files in scope | 48 `.gen.go` | `provider/*/gen/`, `inventory/` | regenerate via `make build` |
64+
| Name collisions | `Step` only | repo-wide | targets declared nowhere; `Step` only as `console.Step` |
65+
66+
### Subpackage disposition
67+
68+
Neither `claimcheck/` nor `server/` existed when the phases were written.
69+
70+
**`claimcheck/`** — the build gate that holds `+devlore:claim=` directives to their call graphs. Nearly
71+
rename-inert: it hardcodes only `pkg/assert` and `pkg/fsroot` as trust boundaries, and its test loads the
72+
whole module by pattern (`github.com/NobleFactor/devlore-cli/...`), which the rename does not change. Moves
73+
with the directory in Phase 5. One doc-comment example names `"./pkg/op/provider/..."` and needs updating.
74+
75+
**`server/`** — the HTTP/2 wire listener bridging a run's `ControlPlane` to a remote consumer. It uses
76+
`op.ControlPlane`, `op.RunStatus`, and the `op.Control*` family, **none of which this rename touches**, so it
77+
is affected by Phase 5 alone. Moves with the directory.
78+
79+
Both are edit-eligible on the same terms as `provider/` and `inventory/` — see Q2.
80+
81+
### Additions since the last audit, checked for rename impact
82+
83+
Method claims (`MethodClaims`, `ClaimDeterministic`), the run-state machine (`RunStatus`, `Phase`,
84+
`Condition`), the control plane (`ControlPlane`, `ControlCommand`, `ControlEvent`), sealed provider resources,
85+
and the conversion rules (`losesMeaning`, `readAgainstField`, `explainRefusal`) name claims, control, and
86+
conversion — **no graph-structure vocabulary**, and none collides with a target name.
87+
88+
The exception is `reportGraphReach`, added by #677, which the appendix covers with the rest.
89+
90+
### What moved between audits
91+
92+
Recorded so the scale of drift is visible: this plan sat untouched for three months while the package it
93+
renames grew substantially, and a phase scoped from the old numbers would have been badly wrong.
94+
95+
| Element | Audited 2026-05-26 | Audited 2026-08-27 | |
7196
| --- | --- | --- | --- |
7297
| `pkg/op/` root `.go` files | 62 | **108** | +74% |
7398
| `provider/` files | 76 | **238** | +213% |
@@ -117,50 +142,142 @@ workflow
117142

118143
Sequencing is collision-safe: Phase 1 must precede Phase 2 (frees the name `Node`). All other phases are independent.
119144

120-
### Appendix: Name Mapping — TO BE WRITTEN
145+
### Appendix: Name Mapping (audited 2026-08-27)
121146

122-
The table above is five rows: the top-level types, one per phase. **Nothing maps the derived identifiers**, and
123-
goal 4 promises "each phase is a pure rename so reviewers can verify by inspection" — without the appendix a
124-
reviewer has no reference to inspect the diff against.
147+
Goal 4 promises "each phase is a pure rename so reviewers can verify by inspection." This is the reference a
148+
reviewer inspects against. It covers the **exported, non-test surface of `pkg/op`**; unexported and test
149+
identifiers follow the same rules mechanically, and the hazards below apply to them equally.
125150

126-
It is derivable, since there are no structural changes. Scope, measured 2026-08-27:
151+
#### The rules
127152

128-
| Word | Exported identifiers containing it |
129-
| --- | --- |
130-
| `Graph` | **53** |
131-
| `Subgraph` | **37** |
132-
| `RecoveryStack` | **18** |
133-
| `ExecutableUnit` | 3 |
153+
1. `Graph` → `Definition`, `GraphExecutor` → `Executor`, `Subgraph` → `Block`, `RecoveryStack` → `Ledger`.
154+
2. **`Node` is ambiguous by construction.** It maps to `Step` *and* is the target of `ExecutableUnit`, so it
155+
appears on both sides. For every identifier containing it, ask **which sense it carries**: the leaf becomes
156+
`Step`; the abstract vertex keeps `Node`.
157+
3. An identifier naming no renamed concept keeps its name even when its receiver type changes.
158+
4. **Not every `Node` is ours** — see §Do not rename.
159+
160+
#### Types
161+
162+
| Current | New | |
163+
| --- | --- | --- |
164+
| `Graph` | `Definition` | |
165+
| `GraphExecutor` | `Executor` | |
166+
| `GraphSpec` | `DefinitionSpec` | |
167+
| `Subgraph` | `Block` | |
168+
| `SubgraphSpec` | `BlockSpec` | |
169+
| `RecoveryStack` | `Ledger` | |
170+
| `ExecutableUnit` | `Node` | abstract vertex; frees nothing until Phase 1 vacates `Node` |
171+
| `ExecutableUnitSpec` | `NodeSpec` | **collides with today's `NodeSpec`** until Phase 1 renames it |
172+
| `Node` | `Step` | leaf |
173+
| `NodeSpec` | `StepSpec` | must precede the `ExecutableUnitSpec` rename |
134174

135-
Plus **14 files** whose names carry a renamed word: `graph.go`, `graph_executor.go`, `subgraph.go`,
136-
`nodeid.go`, `executable_unit.go`, `recovery_stack.go`, and their tests.
175+
#### Constructors and package functions
137176

138-
**Three classes need judgment, not derivation.**
177+
| Current | New |
178+
| --- | --- |
179+
| `NewGraph` | `NewDefinition` |
180+
| `NewGraphSpec` | `NewDefinitionSpec` |
181+
| `NewGraphExecutor` | `NewExecutor` |
182+
| `NewSubgraph` | `NewBlock` |
183+
| `NewSubgraphSpec` | `NewBlockSpec` |
184+
| `NewNode` | `NewStep` |
185+
| `NewNodeSpec` | `NewStepSpec` |
186+
| `NewRecoveryStack` | `NewLedger` |
187+
| `NewChildRecoveryStack` | `NewChildLedger` |
188+
| `LoadGraph` | `LoadDefinition` |
189+
| `SaveGraph` | `SaveDefinition` |
190+
| `SerializeGraphs` | `SerializeDefinitions` |
191+
| `ValidateGraph` | `ValidateDefinition` |
192+
193+
**`LoadGraph` → `LoadDefinition` is worth noting**: `plan.Provider` already has a method of that name, in a
194+
different package, returning `*op.Graph`. After the rename the two agree — `plan.Provider.LoadDefinition`
195+
returns a `*workflow.Definition` by calling `workflow.LoadDefinition`. Not a collision; a convergence.
196+
197+
#### Methods whose own name changes
198+
199+
| Current | New | Why |
200+
| --- | --- | --- |
201+
| `Graph.Subgraphs` | `Definition.Blocks` | names the composite |
202+
| `Graph.SubgraphByID` | `Definition.BlockByID` | |
203+
| `Graph.Nodes` | `Definition.Steps` | returns leaves |
204+
| `Subgraph.Subgraphs` | `Block.Blocks` | |
205+
206+
#### Hooks
207+
208+
| Current | New | Why |
209+
| --- | --- | --- |
210+
| `FireSubgraphStart` / `FireSubgraphComplete` | `FireBlockStart` / `FireBlockComplete` | composite |
211+
| `OnSubgraphStart` / `OnSubgraphComplete` | `OnBlockStart` / `OnBlockComplete` | |
212+
| `FireNodeStart` / `FireNodeComplete` | `FireStepStart` / `FireStepComplete` | fired per LEAF dispatch |
213+
| `OnNodeStart` / `OnNodeComplete` | `OnStepStart` / `OnStepComplete` | |
214+
215+
#### Keeps its name — verify by ABSENCE from the diff
216+
217+
A table of only the changes cannot distinguish "correctly unchanged" from "missed". These must not move:
218+
219+
| Identifier | Why it stays |
220+
| --- | --- |
221+
| `GenerateNodeID` | Mints ids for the abstract vertex, not the leaf — see below the table |
222+
| `Edge` | planning-time connection; names no renamed concept |
223+
| `Receipt` | durable entry; unchanged per the taxonomy |
224+
| `RecoverySite` | name is accurate as-is — see Out of Scope |
225+
| `Binding` and its variants | slot binding; names no renamed concept |
226+
| `Graph.Checksum`, `.Edges`, `.Kind`, `.Origin`, `.Root`, … | receiver changes; the name itself is unaffected |
139227

140-
`Node` is ambiguous by construction — it maps to `Step` *and* is the target of `ExecutableUnit`, so it appears
141-
on both sides of the mapping. Every identifier containing it needs a decision about which sense it carries.
142-
The proof is `GenerateNodeID`, whose doc says "unique node IDs across all plan bindings" and which
143-
`pkg/op/provider/flow/helpers.go` calls as:
228+
**`GenerateNodeID` in detail**, because Phase 1 originally had it wrong. `pkg/op/provider/flow/helpers.go`
229+
calls it as:
144230

145231
```go
146232
GenerateNodeID(string(Subgraph))
147233
```
148234

149-
It mints ids for **subgraphs too**, so it names the abstract vertex — which under the new taxonomy is `Node`,
150-
meaning **it keeps its name**. A mechanical `Node → Step` sweep would rename it `GenerateStepID` and quietly
151-
make it wrong: an identifier claiming to mint leaf ids while minting them for `Block`s as well. Phase 1 before
152-
Phase 2 protects the *types* from this collision; nothing protects derived identifiers.
235+
It mints ids for composites as well as leaves, so it names the **abstract vertex** — which under the new
236+
taxonomy is `Node`, the name it already has. A mechanical `Node → Step` sweep renames it `GenerateStepID` and
237+
quietly makes it wrong: an identifier claiming to mint leaf ids while minting them for `Block`s too. Phase 1's
238+
target list said exactly that until this appendix was written.
239+
240+
#### Do not rename — NOT ours
153241

154-
File names are not all mechanical either. `graph.go` → `definition.go` and `graph_executor.go` → `executor.go`
155-
are clear; `nodeid.go` follows whatever `GenerateNodeID` decides.
242+
`pkg/op/default_eval.go` and `deferred_default.go` use `text/template/parse`, whose vocabulary collides with
243+
ours:
156244

157-
And prose inside identifiers — `SerializeGraphs`, `descendantNodes`, `SubgraphChild`, `NewGraphSpec` — reads
158-
differently after the swap, some of it carrying the same ambiguity.
245+
```go
246+
action, ok := tree.Root.Nodes[0].(*parse.ActionNode)
247+
```
159248

160-
**Identifiers that KEEP their name must be listed explicitly.** A table of only the changes cannot distinguish
161-
"correctly unchanged" from "missed", and `GenerateNodeID` is exactly that case.
249+
`parse.ActionNode`, `parse.PipeNode`, `parse.StringNode`, `parse.IdentifierNode`, `parse.NumberNode`,
250+
`parse.BoolNode`, `parse.FieldNode`, `parse.CommandNode` — **and `.Nodes`, a field on a stdlib type.** A
251+
mechanical sweep over the word `Node` rewrites `tree.Root.Nodes` and fails to compile. Phase 1 must exclude
252+
these by qualifier, not by name.
253+
254+
#### Files
255+
256+
| Current | New |
257+
| --- | --- |
258+
| `graph.go` | `definition.go` |
259+
| `graph_executor.go` | `executor.go` |
260+
| `subgraph.go` | `block.go` |
261+
| `node.go` | `step.go` |
262+
| `executable_unit.go` | `node.go` — **only after `node.go` vacates** |
263+
| `recovery_stack.go` | `ledger.go` |
264+
| `nodeid.go` | keeps its name, following `GenerateNodeID` |
265+
266+
Test files follow their subject: `graph_executor_test.go` → `executor_test.go`, `subgraph_test.go` →
267+
`block_test.go`, and so on. `graph_number_fidelity_test.go` and `graph_format_identity_test.go` name the
268+
Definition, so both take `definition_`.
269+
270+
#### Counts, for scoping
271+
272+
| Word | Exported identifiers containing it |
273+
| --- | --- |
274+
| `Graph` | 53 |
275+
| `Subgraph` | 37 |
276+
| `RecoveryStack` | 18 |
277+
| `ExecutableUnit` | 3 |
162278

163-
Written under [#716](https://github.com/NobleFactor/devlore-cli/issues/716).
279+
23 of those are exported and non-test — the surface tabled above. The remainder are unexported helpers and
280+
test fixtures, which follow the same rules.
164281

165282
## Implementation Phases
166283

@@ -172,7 +289,8 @@ Single concept rename of the leaf struct. Frees the name `Node` for Phase 2.
172289

173290
**Targets:**
174291
- `pkg/op/graph.go:380` — struct declaration carrying `Layer` + `Origin` fields
175-
- Internal symbols that ripple: `NewNode → NewStep`, `GenerateNodeID → GenerateStepID`, `NodeID → StepID`, `node`-named locals
292+
- Internal symbols that ripple: `NewNode → NewStep`, `NodeSpec → StepSpec`, `node`-named locals REFERRING TO LEAVES
293+
- **`GenerateNodeID` KEEPS its name** — corrected 2026-08-27. This list previously said `GenerateNodeID → GenerateStepID`, `NodeID → StepID`. That is wrong: `flow/helpers.go` calls it as `GenerateNodeID(string(Subgraph))`, so it mints ids for composites as well as leaves. It names the ABSTRACT VERTEX, which under the new taxonomy is `Node`. See the appendix.
176294
- All consumer references `op.Node` → `op.Step`
177295

178296
**Files:**
@@ -291,9 +409,21 @@ after means shipping a constant named for the type it replaced. Tracked as
291409

292410
## Open Questions
293411

294-
- [ ] **Q2: Subpackage edit bans beyond `starlarkbridge/`?** `provider/`, `inventory/`, `sops/` move with the directory in Phase 5. The starlarkbridge ban means I never edit its contents directly. Same treatment for the others, or are they edit-eligible?
295-
- [ ] **Q3: GitHub issue.** Per the standard workflow, an issue tracks this plan. Issue number goes in frontmatter once created (post-prerequisite-merge).
296-
- [ ] **Q4: Plan template adherence.** This plan deviates slightly from `docs/plans/TEMPLATE.md` (richer phase descriptions; no Migration Path section since rename has no user-facing migration). Confirm acceptable.
412+
- [x] **Q2: Subpackage edit bans.** ~~`provider/`, `inventory/`, `sops/` move with the directory in Phase 5.~~
413+
Restated 2026-08-27: `sops/` has left the package, and `claimcheck/` and `server/` have arrived. The
414+
starlarkbridge edit ban has since been lifted, so all five subpackages are edit-eligible on the same terms.
415+
Dispositions are in §Subpackage disposition.
416+
- [x] **Q3: GitHub issue.** Epic [#451](https://github.com/NobleFactor/devlore-cli/issues/451), with
417+
[#716](https://github.com/NobleFactor/devlore-cli/issues/716) (this re-audit) and
418+
[#715](https://github.com/NobleFactor/devlore-cli/issues/715) (the role rename) beneath it.
419+
- [ ] **Q4: Plan template adherence.** `docs/plans/TEMPLATE.md` gained a **Test Plan** section on 2026-08-27,
420+
which this plan does not have. For a pure rename the test plan is "every existing test passes unchanged" —
421+
which §Verification (per phase) already states, and which is the whole assertion. Confirm that section
422+
satisfies the requirement rather than adding a redundant one.
423+
- [ ] **Q5: Documentation churn.** Added 2026-08-27. §Documentation Audit predates
424+
`3.2-projected-provider-api.md`, `3.6-method-classification.md`, `4.5-fsroot-variants.md`, and the provider
425+
catalog, all of which now describe `pkg/op` in prose a pure rename churns. In scope for the audit phase, or
426+
a follow-up? Stating it beats discovering it mid-phase.
297427

298428
## Files to Create/Modify
299429

0 commit comments

Comments
 (0)