Plan the performance improvements
This commit is contained in:
@@ -1,208 +1,448 @@
|
||||
# Implement ReleaseKit adoption
|
||||
# Implement the performance audit revisions
|
||||
|
||||
Status: Complete. All seven stages below have been implemented and verified.
|
||||
The [ReleaseKit adoption roadmap](releasekit.md) owns the target state and
|
||||
policy choices; this plan records the execution checklist. Use ReleaseKit v0.2.0
|
||||
at tagged commit
|
||||
`e030794969fb7787e647a90bbc4eb81bd0610f07` for the initial migration.
|
||||
Do not publish a real ConfigKit version as part of implementation. Keep the
|
||||
current release procedure authoritative until the replacement is working.
|
||||
Follow the task-specific reading guide in [development.md](../development.md)
|
||||
and avoid adding gates, compatibility promises, or restrictions beyond the
|
||||
roadmap and adopted policies. Stages 3–5 are one documentation-and-machinery
|
||||
cutover; do not commit or hand off their intermediate state as a release-ready
|
||||
candidate.
|
||||
Status: Planned. Audience: a Luna coding agent implementing one stage at a time,
|
||||
in numerical order. The [performance audit roadmap](performance-audit.md) owns
|
||||
the target and rationale. This plan replaces the completed ReleaseKit plan,
|
||||
which remains available in Git history at `0c77dee`.
|
||||
|
||||
## Stage 1: Select Go and declare the release tool — Complete
|
||||
Planning baseline: `0c77deed05417edb32f42c7bf24df2fdc2581a25`.
|
||||
The production baseline is unchanged from the audit's `48619de` revision.
|
||||
Keep the earlier Path.String sizing and combined final-metadata traversal
|
||||
improvements. This sprint changes private algorithms, not public API,
|
||||
configuration semantics, dependencies, Go minimum, or release gates.
|
||||
|
||||
1. Identify the latest locally available patch in the newest stable Go series
|
||||
available in the development environment. Make it the `go` on `PATH` and
|
||||
verify it with `GOTOOLCHAIN=local go version`. Keep ConfigKit's current
|
||||
`go.mod` `go` minimum until the release-workflow cutover in Stage 4: the
|
||||
existing release checker still selects Go 1.25 and cannot validate a module
|
||||
requiring Go 1.26. Do not substitute an automatically downloaded toolchain
|
||||
during later validation.
|
||||
2. Using that same Go executable, add
|
||||
`gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@v0.2.0` as a
|
||||
`go.mod` tool dependency (the Go `tool` directive and its module
|
||||
requirement). Update `go.sum`, run `go mod tidy`, and inspect the module
|
||||
diff. Preserve ConfigKit's runtime dependency boundary: production library
|
||||
packages must not import ReleaseKit. Do not introduce a second tool-version
|
||||
pin or an `@version` installation path in the release procedure.
|
||||
3. Prepare the module cache and build the selected CLI package with that Go
|
||||
executable into a temporary path outside the worktree. Confirm that the
|
||||
resolved ReleaseKit module is v0.2.0 and that the built executable runs.
|
||||
Review actual dependency and license treatment under the
|
||||
[OSS policy](../policy/oss.md); a tool used only for development and release
|
||||
work does not by itself require an attribution entry.
|
||||
## Working instructions
|
||||
|
||||
Completion evidence: `go.mod` retains its current Go minimum and selects the
|
||||
pinned ReleaseKit tool, `go.sum` is consistent, `go mod tidy` leaves no
|
||||
unintended changes, the module-selected executable builds with the selected
|
||||
local Go, and the ordinary offline Go suite still passes after dependencies
|
||||
are prepared. If the new tool dependency itself requires a higher minimum,
|
||||
handle that compatibility change together with the cutover rather than
|
||||
leaving the current release checker unusable.
|
||||
- Read [development.md](../development.md), the applicable agent, architecture,
|
||||
testing, and documentation policies, and owning contract/test files before
|
||||
each stage. Use the graph tools for code discovery as instructed by AGENTS.md.
|
||||
- Preserve user changes. Implement only the current stage and its regressions;
|
||||
update its status/evidence here and commit the validated unit with a short
|
||||
plain-English message. Do not publish, push, or modify consumer dependencies.
|
||||
- Operation indexes are private phase-local data. Inspection indexes are fully
|
||||
built before publication and only read afterward. Returned records remain
|
||||
detached. Keep effective and historical indexes separate with independently
|
||||
owned mutable path storage.
|
||||
- Preserve the existing [configuration contract](../config.md): presence,
|
||||
null/empty distinctions, composition, diagnostics, chronology, sensitivity,
|
||||
callback lifetime, secret isolation, and handle closure. Do not add rejection
|
||||
rules, limits, stricter callbacks, concurrency promises, or complexity guarantees.
|
||||
- Run each stage's focused checks and `./scripts/check.sh` before handing off
|
||||
production changes. Run `go test -race ./internal/engine` after retained-index
|
||||
or ownership changes, and the full race suite in Stage 18. Reuse checks for
|
||||
unchanged content. No new CI wait, release gate, or performance threshold.
|
||||
- Prefer algorithm reasoning for this sprint. Benchmark runs are not prerequisites.
|
||||
Optional measurements use the same prepared local Go, offline dependencies,
|
||||
sequential runs, and artifacts outside repositories. Favor B/op and allocs/op
|
||||
on the busy host; do not infer CPU improvements from noisy timings.
|
||||
- Extend existing behavioral tests for missing risks, not traversal counts.
|
||||
Small test-only baseline algorithms may support bounded differential coverage.
|
||||
Do not keep alternate production engines or switches. If the selected algorithm
|
||||
cannot preserve behavior, record the discrepancy and seek review rather than
|
||||
strengthening the contract or silently dropping work.
|
||||
|
||||
## Stage 2: Add ConfigKit's ReleaseKit profile — Complete
|
||||
## Resolved implementation choices
|
||||
|
||||
1. Add `releasekit.json` at the repository root with `product` set to
|
||||
`ConfigKit`, `remote` set to `origin`, and `expected_push_url` set to
|
||||
`https://gitea.maximumdirect.net/eric/ConfigKit.git`. Select
|
||||
`validation.go.race: true`, `validation.go.full_vet: true`, and
|
||||
`validation.go.compile_targets` in this order: `linux/amd64`, `linux/arm64`.
|
||||
Omit `build`, `delivery`, `checks`, and the other optional validation
|
||||
selections. This is a source-only release; macOS is best effort.
|
||||
2. Add one small, offline ConfigKit-owned test of the committed profile's
|
||||
selected identity, endpoint, and checks. Keep it limited to configuration
|
||||
wiring and the agreed gate set; do not replicate ReleaseKit's publication,
|
||||
recovery, or Go-check implementation tests. Stage 6 will exercise the
|
||||
profile with the actual tool against an isolated remote.
|
||||
1. Containment and path deduplication use canonical token spelling, as today.
|
||||
Metadata/document queries additionally enforce contextual key/index shape.
|
||||
These predicates remain distinct.
|
||||
2. Use a small private engine prefix trie with canonical **escaped** pointer
|
||||
tokens and integer IDs into owner-held slices. Root is zero tokens; `/`
|
||||
is one empty token. Scan separator boundaries without decoding/rejoining
|
||||
tokens. Escapes contain no slash. The trie does not validate document shape.
|
||||
3. The helper returns IDs, not values/provenance. Owners select deepest ancestor,
|
||||
earliest inserted ancestor/intersection, or all relevant IDs, explicitly
|
||||
restoring owner order. No general path framework or public hook is introduced.
|
||||
4. Sensitivity uses a worklist: ordinary dependencies activate on intersection,
|
||||
while directed inheritance links activate on a classified ancestor/equal
|
||||
path of their dependency. Preserve both rules.
|
||||
5. Inspection retains full replay and on-demand safe rendering. Prepare immutable
|
||||
coalesced resolution descriptors and inheritance lookup data once, with no
|
||||
per-field tree or rendered-explanation cache.
|
||||
6. Defer branch-local replay, public metadata-copy redesign, global schema caching,
|
||||
and complex contributor-trace membership indexing. Their ownership/memory/
|
||||
equality risks exceed the selected scope. Existing clones and linked traces
|
||||
stay in place. No new dependency, pool, or package-global mutable cache is needed.
|
||||
|
||||
Completion evidence: the profile is valid JSON, the focused test and ordinary
|
||||
Go suite pass, and review shows only the selected gates and no binary or hosted
|
||||
delivery configuration.
|
||||
## Stage 1: Confirm the baseline and semantic evidence
|
||||
|
||||
## Stage 3: Align release policy with the adopted workflow — Complete
|
||||
Scope: orientation and test-only evidence, with no optimization yet.
|
||||
|
||||
1. Revise [the release policy](../policy/release.md) so candidate preparation
|
||||
explicitly publishes the committed candidate to authoritative `main`
|
||||
before the one ReleaseKit `publish` invocation validates it and publishes
|
||||
the annotated tag. Keep the checked-in note and tag as the only deliverables,
|
||||
successful intended-tag publication as completion, and CI, macOS, hosted
|
||||
delivery, and consumer retrieval outside release gates.
|
||||
2. Replace references to the local release scripts and fixed Go 1.25 release
|
||||
baseline with the selected local Go executable, the current `go.mod`
|
||||
minimum, the module-selected ReleaseKit CLI, its one race suite with
|
||||
test-time vet disabled, full vet, and Linux amd64/arm64 package compilation.
|
||||
State that preparation records the initial stable release of the newest
|
||||
locally available Go series in `go.mod`, retaining a higher patch minimum
|
||||
only when required by a dependency or specific correctness fix. Use the
|
||||
latest locally available compatible patch in that series for ReleaseKit's
|
||||
build and validation, and review any minimum-version increase under
|
||||
existing compatibility rules. Keep dependency acquisition and tool build
|
||||
before offline candidate validation; do not add a separate successful test
|
||||
or CI run as a publication prerequisite.
|
||||
3. Align the guard descriptions with ReleaseKit v0.2.0: use its release-note
|
||||
H1 and exact effective push-URL checks, rather than claiming an automated
|
||||
exact-first-line or configured fetch-URL check. Retain the required
|
||||
`# ConfigKit <version>` first-line format for notes, the source/tag
|
||||
immutability rules, and the existing recovery principles. Do not require
|
||||
per-test skip listings; test failures still block publication.
|
||||
1. Inspect status/revisions. Read the audit and configuration contract sections
|
||||
for metadata, sensitivity, explanation, resolution, and overrides, plus their
|
||||
implementation/test owners.
|
||||
2. Run `./scripts/check.sh`. Record revision, local `go version`, result, and
|
||||
environmental limitations in an evidence subsection here. Do not repeat or
|
||||
revise the completed startup timing campaign.
|
||||
3. Identify existing coverage for numeric shapes, removed paths, escaped keys,
|
||||
inheritance, callback detachment, and independent loads. Add test-only reference
|
||||
helpers if useful for later containment, coverage/coalescing, overlap, and
|
||||
sensitivity equivalence tests. Keep fixtures bounded and deterministic; do not
|
||||
copy the loader. Helpers may instead accompany their first consuming stage.
|
||||
|
||||
Completion evidence: policy and roadmap agree on order, gates, compatibility,
|
||||
and completion; no policy passage still describes the retired script or its
|
||||
stronger automated guards as current behavior.
|
||||
Done: baseline checks recorded and semantic test owners identified. Existing
|
||||
contracts/tests are authoritative; reference algorithms add equivalence evidence,
|
||||
not new public guarantees. A documentation-only stage needs documentation checks.
|
||||
|
||||
## Stage 4: Replace the maintainer release runbook — Complete
|
||||
## Stage 2: Make presence-only queries lightweight
|
||||
|
||||
1. Revise [the runbook](../release.md) into copyable steps for the adopted
|
||||
process. During this cutover, move `go.mod` from its current minimum to the
|
||||
first stable release of the newest Go series available in the development
|
||||
environment (for example, `go 1.26.0` when using Go 1.26.8), unless a
|
||||
dependency or specific correctness fix needs a higher patch minimum. Have
|
||||
the runbook derive the series from `GOTOOLCHAIN=local go env GOVERSION` and
|
||||
use `go mod edit` to record its `.0` release, without lowering an existing
|
||||
required higher patch minimum. Keep that series' latest locally available
|
||||
compatible patch first on `PATH` for both the tool build and validation.
|
||||
Explain the minimum-Go compatibility impact and version choice, including
|
||||
the pre-v1.0.0 minor-release rule. Prepare
|
||||
dependencies, then build the module-selected `cmd/releasekit` with that
|
||||
executable into temporary storage outside the repository. Use the native
|
||||
executable for publication so its exit status and diagnostic state are
|
||||
preserved. Its child Go commands must find the same selected `go` on `PATH`;
|
||||
the old `CONFIGKIT_BASELINE_TOOLCHAIN` selector cannot choose them.
|
||||
2. Keep ordinary candidate preparation: check access to the authoritative
|
||||
remote, choose an unused stable version, review compatibility and content,
|
||||
write `docs/releases/<version>.md` with the exact ConfigKit first line and
|
||||
license footer, retire completed roadmaps, and commit the entire candidate.
|
||||
Do not turn those reviews into additional approval gates. Push only that
|
||||
committed candidate to authoritative `main` using the literal authoritative
|
||||
URL and `HEAD:refs/heads/main` refspec, with implicit tag following
|
||||
disabled. ReleaseKit requires the remote `main` to equal the candidate
|
||||
before it validates. A failure before this push leaves publication
|
||||
unstarted; a failed validation after it leaves an untagged `main` candidate
|
||||
that must be corrected by a new commit and another validation.
|
||||
3. Document one `releasekit publish vMAJOR.MINOR.PATCH` invocation using the
|
||||
built, module-selected executable. Describe its selected race suite, full
|
||||
vet, Linux package builds, release-note and effective-push-URL guards,
|
||||
exact tag publication, and confirmed-tag completion. Keep `check` optional
|
||||
for diagnosis, not a repeated required pass. Update the partial/unknown
|
||||
push recovery directions to ReleaseKit's reported candidate, endpoint,
|
||||
tag-object ID, and bounded authoritative-state reconciliation. Preserve
|
||||
optional post-publication consumer verification and no-CI-wait behavior.
|
||||
Remove old script commands, Go 1.25 pin examples, and promises of verbose
|
||||
skipped-test output.
|
||||
Roadmap candidate 1. Owner: `internal/engine/metadata.go`.
|
||||
|
||||
Completion evidence: a maintainer can follow the runbook from a clean checkout
|
||||
through confirmed tag publication without a ConfigKit release wrapper or a
|
||||
second required Go/test run; all commands, version placeholders, and documented
|
||||
failure states match ReleaseKit v0.2.0. Do not execute its real publication
|
||||
command in this stage.
|
||||
1. Make `Metadata.IsExplicit` validate effective path/shape and read the stored
|
||||
boolean, without calling `Lookup`, cloning origins, or projecting inheritance.
|
||||
A shared private effective-field lookup may serve both methods; `Lookup`
|
||||
continues returning complete detached records.
|
||||
2. Format each query pointer once per lookup. Preserve root, zero metadata,
|
||||
invalid/unknown/removed paths, parsed numeric tokens, and explicit key/index
|
||||
distinctions. Leave `Resolution.IsExplicit` entry-state semantics unchanged.
|
||||
3. Extend metadata/presence tests only where agreement with `Lookup` lacks
|
||||
coverage: direct/inherited input, defaults, and explicit false/zero/null.
|
||||
|
||||
## Stage 5: Retire duplicated machinery and update developer guidance — Complete
|
||||
Validate: `go test ./internal/engine -run 'Metadata|Presence|Explicit|Inherited'`,
|
||||
relevant root facade tests, and the everyday check. No allocation assertion.
|
||||
|
||||
1. Remove `scripts/release.sh`, `scripts/release-check.sh`, and
|
||||
`release_publish_test.go` after Stages 1–4 supply the replacement. Remove
|
||||
`TestCheckScriptsReleaseGates` and its now-unused helpers from
|
||||
`release_check_test.go`. Preserve
|
||||
`TestDevelopmentCheckHandlesFilenamesAndStopsOnFailure` and
|
||||
`scripts/check.sh`; rename the test file if helpful so its name reflects
|
||||
its remaining owner. Retain the small Stage 2 profile-wiring test. Do not
|
||||
transplant the old publication guard/recovery matrix into ConfigKit tests.
|
||||
2. Update [the development guide](../development.md) to point to the new
|
||||
release runbook, remove retired-script references and the fixed release
|
||||
baseline, and adjust its task-to-test map. Keep the everyday development
|
||||
check and release validation distinct. Review other live references to the
|
||||
removed scripts and update only those made stale by this migration;
|
||||
historical release notes remain unchanged.
|
||||
## Stage 3: Detect inheritance without constructing paths
|
||||
|
||||
Completion evidence: no live release instruction invokes a removed script;
|
||||
the default suite and `./scripts/check.sh` pass with the selected Go and
|
||||
prepared dependencies; the retained tests protect development checks and
|
||||
profile wiring without duplicating ReleaseKit's generic behavior.
|
||||
Roadmap candidate 9. Owner: `internal/engine/inheritance_load.go`.
|
||||
|
||||
## Stage 6: Exercise the migration without publishing ConfigKit — Complete
|
||||
1. Replace detection's full path-building walk with a nil-safe boolean visitor:
|
||||
inspect mapping keys for `extends`, recurse into values/sequence children,
|
||||
and return immediately on a match.
|
||||
2. Leave validation, expansion order, provenance, and budgets unchanged.
|
||||
Detection is not validation and must still find nested invalid syntax.
|
||||
3. Reuse inheritance tests; add missing sequence-contained or invalid nested
|
||||
cases without assertions about how many nodes were visited.
|
||||
|
||||
1. Build ReleaseKit from the candidate's `go.mod` selection with the latest
|
||||
selected local Go patch for that minimum's series. Use that same executable
|
||||
for ReleaseKit's validation, without requiring its patch number to equal
|
||||
the `go.mod` minimum. In disposable Git fixtures, use
|
||||
ConfigKit's selected profile with only `expected_push_url` changed to a
|
||||
temporary bare remote, and provide a matching committed fixture release
|
||||
note. Never push a ConfigKit tag or source commit to its real remote.
|
||||
2. Push a committed fixture candidate to temporary `main` and run the built
|
||||
`publish` command with a deliberately failing fixture test. Confirm
|
||||
validation fails and creates no release tag, while `main` remains at that
|
||||
candidate. Correct and commit the fixture, push the new candidate to
|
||||
temporary `main`, and run `publish` again. Confirm one race-enabled standard
|
||||
suite, one full vet pass, and one CGO-disabled package compile for each
|
||||
selected Linux target in that successful invocation; confirm the remote
|
||||
annotated tag identifies the corrected candidate and contains the checked-in
|
||||
note. Record child Go invocations with a fixture-only forwarding executable
|
||||
on `PATH`, or use equivalent direct evidence, rather than inferring the
|
||||
selected command count merely from success.
|
||||
Validate: `go test ./internal/engine -run 'Inheritance|Inherited'` and the
|
||||
everyday check. Inputs without inheritance still need a linear scan.
|
||||
|
||||
Completion evidence: the isolated failure and success paths demonstrate the
|
||||
selected profile, module-selected tool, command order, gates, and tag-only
|
||||
publication. No ConfigKit ref is pushed to its real remote.
|
||||
## Stage 4: Compare path tokens without whole-pointer formatting
|
||||
|
||||
## Stage 7: Check endpoint failure and finish the cutover review — Complete
|
||||
Roadmap candidate 2. Owners: engine `path.go`, `resolution.go`, `metadata.go`.
|
||||
|
||||
1. In a fresh disposable fixture/version without an existing tag, check that
|
||||
a wrong effective push URL is rejected before validation or tag
|
||||
publication. Do not reuse the version already published in Stage 6, which
|
||||
would make the existing-tag guard obscure the endpoint result.
|
||||
2. Compare the runbook's recovery directions with ReleaseKit's reported state
|
||||
for a failed or uncertain tag push. Repair any mismatch in the runbook;
|
||||
do not duplicate ReleaseKit's recovery machinery in ConfigKit. This is a
|
||||
bounded migration exercise, not a new per-release gate or a requirement to
|
||||
wait for CI.
|
||||
3. Re-run the affected repository checks after any corrections. Review the
|
||||
final policy, runbook, development guide, and roadmap together for a
|
||||
coherent process; confirm that only intended files changed and that no
|
||||
real ConfigKit release or push occurred.
|
||||
1. Add private token-spelling equality. Key/parsed segments compare literal
|
||||
bytes; two indexes compare integers. For index versus key/parsed, render the
|
||||
index into stack scratch space with `strconv.AppendInt` and compare bytes.
|
||||
Do not parse literal tokens as integers: `01`, `+1`, and `1` differ.
|
||||
2. Implement `pathContains` with existing validity/depth checks and token-prefix
|
||||
equality. Root behavior remains unchanged. Escaping is injective, so raw
|
||||
token spelling comparison preserves canonical pointer equivalence.
|
||||
3. Replace textual comparison in `matchesPathShape` with token equality, then
|
||||
retain its existing explicit/contextual shape checks and candidate-side
|
||||
handling. Apply the same spelling predicate to local textual path deduplication.
|
||||
4. Differentially compare with the String-based baseline over roots, invalid
|
||||
paths, empty/slash/tilde/numeric keys, parsed tokens, nested paths, and integer
|
||||
extrema. Reuse existing effective/historical query-shape coverage.
|
||||
|
||||
Completion evidence: the wrong-endpoint fixture fails for the intended reason,
|
||||
recovery guidance matches ReleaseKit v0.2.0, tests and documentation checks
|
||||
pass, and the repository is ready for a separately authorized release.
|
||||
Validate: `go test ./internal/engine -run 'Path|Metadata|Resolution|Override|Inheritance'`
|
||||
and the everyday check. Public `Path.String` stays unchanged.
|
||||
|
||||
## Stage 5: Format sorting keys once per item
|
||||
|
||||
Roadmap candidate 2. Owners: engine resolution, overlay, override application,
|
||||
document comparison, and diagnostics.
|
||||
|
||||
1. Decorate path-bearing items with precomputed canonical pointers, sort with
|
||||
existing comparisons/tie-breakers, then project back. Cover
|
||||
`orderedResolutionRecords`, `displacedOrigins`, `affectedOverrideOrigins`,
|
||||
and the final delta sort in `compareConfigurationValues`.
|
||||
2. In `canonicalDiagnostics`, precompute paths without changing comparator
|
||||
precedence, primary/related location ordering, or standalone comparator use.
|
||||
Do not add permanent pointer fields to every record for sorting.
|
||||
3. Gather recursive displaced definitions into one owned output and sort at
|
||||
the outer owner, avoiding repeated sorting of the same nested subtree.
|
||||
Preserve final lexical order and duplicate behavior.
|
||||
4. Reuse ordering tests; add missing tie/escaped-key cases. Do not promise stable
|
||||
order for items whose full comparison is equal.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Resolution|Override|Overlay|Diagnostic|CompareDocument|Provenance'`
|
||||
and the everyday check. Expected benefit is reduced formatting, not measured CPU.
|
||||
|
||||
## Stage 6: Add a private canonical-pointer prefix index
|
||||
|
||||
Scope: one helper plus tests, no caller migration yet.
|
||||
|
||||
1. Add `internal/engine/path_prefix.go`. Nodes have child maps keyed by escaped
|
||||
tokens, terminal integer payload IDs, and the minimum inserted ID within the
|
||||
subtree. IDs are nonnegative owner ordinals; represent absence explicitly.
|
||||
2. Support insertion, ancestor payload visits (root/exact included), descendant
|
||||
payload visits (exact included), and earliest intersecting ID using ancestor
|
||||
IDs and the queried subtree minimum. Preserve multiple IDs at one terminal.
|
||||
No deletion, wildcard search, provider abstraction, or serialization API.
|
||||
3. Tokenize canonical pointers by separator scanning without split slices.
|
||||
Preserve root versus empty keys and `/a` versus `/ab` boundaries. Owners
|
||||
supply canonical pointers from valid paths; no new input validation contract.
|
||||
Retain IDs only, not nodes, credential bytes, or mutable path segments.
|
||||
4. Differentially check results against simple prefix scans for ancestors,
|
||||
descendants, duplicates, insertion minima, escaping, and root/empty tokens.
|
||||
|
||||
Validate: focused helper tests and the everyday check. Storage follows indexed
|
||||
token material/payloads; tests do not fix representation or allocation counts.
|
||||
|
||||
## Stage 7: Index resolution coverage and record reads
|
||||
|
||||
Roadmap candidate 3, first integration. Owner: `internal/engine/resolution.go`.
|
||||
|
||||
1. Index already ordered records after the callback. Select deepest covering
|
||||
ancestor, earliest owner ID for equal depth, matching the current scan.
|
||||
Use this for delta coverage in `runResolution`; retain all validity/helper
|
||||
checks and diagnostic order.
|
||||
2. Add a small snapshot coverage adapter with the same rules for Stage 8.
|
||||
IDs refer to owner-held slices and cannot outlive or survive their reordering.
|
||||
3. Build operation-local read-only mapping lookups for completed before/after
|
||||
trees, reusing `mappingIndex` mechanics without mutating trees. Add a private
|
||||
indexed document lookup variant with the same validity, shape, bounds, and
|
||||
absence checks; retain the plain helper for callers without reuse.
|
||||
4. Cover parent/exact/more-specific records, equal-depth private fixtures,
|
||||
added/removed values, unrecorded changes, and helper-target mismatch.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Resolution|Resolve|Callback|Path'`
|
||||
and the everyday check. Snapshot ownership/contents remain unchanged.
|
||||
|
||||
## Stage 8: Replace per-delta whole-metadata scans
|
||||
|
||||
Roadmap candidate 3, second integration. Owner: engine `load_metadata.go`.
|
||||
|
||||
1. In `applyResolutionMetadata`, build one final pointer/node index and one
|
||||
snapshot coverage index. Reuse final membership for descendant history and
|
||||
field refresh; do not rebuild indexes per delta/field.
|
||||
2. Index delta paths by original delta ID. Enumerate the union of historical
|
||||
and final pointers once, obtain covering delta IDs, and bucket affected pointers
|
||||
by delta. Parse paths only when a retained semantic path is actually needed.
|
||||
Sort buckets lexically and retain original delta processing order.
|
||||
3. Apply exact snapshot events first, descendant history second, effective origin
|
||||
updates third, then final field refresh, as today. Exclude the covering record's
|
||||
own pointer from descendant history and retain the original Previous origins.
|
||||
Handle overlapping delta IDs in reference fixtures without assuming every
|
||||
possible input is disjoint. Normal structural comparison emits disjoint deltas.
|
||||
4. For fields, visit pointers once and process matching delta IDs in original
|
||||
order. For new fields, use snapshot coverage; preserve null/Explicit state,
|
||||
default resolution-origin fallback, and removed-path history.
|
||||
5. Extend existing tests for many disjoint changes, replacement, removed/new
|
||||
descendants, and numeric container-shape changes. A bounded test-only
|
||||
reference metadata update can protect phase/order equivalence.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Resolution|Metadata|Provenance|History|Explain'`,
|
||||
engine race tests, and the everyday check. Complexity is output-sensitive to
|
||||
affected events, not every delta times every field.
|
||||
|
||||
## Stage 9: Collect sensitivity directly from trees
|
||||
|
||||
Roadmap candidate 5. Owner: engine `secret.go`. Keep fixed-point propagation
|
||||
unchanged until Stage 11 so collection is independently reviewable.
|
||||
|
||||
1. Replace temporary pointer/node indexes used only to enumerate classification
|
||||
paths/flags with direct visitors into local path and sensitivity accumulators.
|
||||
Remove the redundant initial final-tree scan; final still participates in
|
||||
the late projection phase before schema/predicate classification.
|
||||
2. Preserve phase precedence: applications; history/dependencies; inheritance;
|
||||
projections then final. Tree/pointer contributions currently install parsed
|
||||
segments, while history/contributor contributions can install typed paths.
|
||||
Preserve those representations and subsequent overwrites.
|
||||
3. Skip reparsing only if the current stored path already has that parsed
|
||||
representation. Otherwise perform the existing parsed replacement. Do not
|
||||
simply substitute explicit walker key/index paths or retain the first shape.
|
||||
4. Retain all historical/removed paths, controls, dependency-only paths, default/
|
||||
dynamic tagged projections, and cloned predicate arguments.
|
||||
5. Add only missing numeric shape-transition, historical predicate, dynamic tag,
|
||||
and predicate-detachment cases in existing sensitivity/inheritance test owners.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Secret|Sensitivity|Inherited|Effective|Explain'`,
|
||||
engine race tests, and the everyday check. No new predicate order/count guarantee.
|
||||
|
||||
## Stage 10: Build and test indexed sensitivity triggers
|
||||
|
||||
Roadmap candidate 6, isolated algorithm. Add private
|
||||
`internal/engine/secret_propagation.go` and focused tests.
|
||||
|
||||
1. Ordinary edges have dependency/target pointers and activate on classified
|
||||
ancestor or descendant intersection. Inheritance links become two directed
|
||||
edges, each activated only by a classified ancestor/equal dependency path.
|
||||
2. Index dependency pointers with payload IDs. A new classified pointer visits
|
||||
ordinary triggers at ancestors and descendants; inheritance triggers only
|
||||
at descendants. Avoid double-visiting exact terminals. Track fired IDs and
|
||||
enqueue a target only when it becomes newly sensitive.
|
||||
3. Seed from the initial sensitive set. Preserve the ordinary dependency filter:
|
||||
the old `secretIntersectsPath` sees only classified pointers present in the
|
||||
collected paths map. Inheritance's `pathIsSecret` does not require membership.
|
||||
Relations use textual spelling, not document query-shape validation.
|
||||
4. Differentially compare final sets to the old fixed-point algorithm for
|
||||
forward/reverse chains, cycles, duplicate edges, classified ancestors/
|
||||
descendants, classified pointers absent from paths, root, escapes/numeric
|
||||
spellings, and mixed ordinary/inheritance graphs. Use no real credentials.
|
||||
|
||||
Validate: focused propagation tests and the everyday check. Match/output-sized
|
||||
work may still be large for broad dependencies; no blanket linear guarantee.
|
||||
|
||||
## Stage 11: Integrate worklist sensitivity into publication
|
||||
|
||||
Roadmap candidate 6, integration. Owner: engine `secret.go`.
|
||||
|
||||
1. Feed collected paths, seeds, dependencies, and inheritance links into Stage
|
||||
10's closure. Remove the production fixed-point loop/unused scan helper after
|
||||
migration; retain the useful reference only in tests.
|
||||
2. Verify full-load effective rendering and explanations for mixed derived/
|
||||
inherited sensitivity, replaced/removed paths, tagged containers, consumed
|
||||
controls, and nested copies. All credentials remain outside trees/indexes.
|
||||
3. Verify independent loads and repeated queries retain no mutable propagation
|
||||
state. Queues and trigger indexes are phase-local and discarded on return.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Secret|Sensitivity|Inheritance|History|Explain|Independent'`,
|
||||
relevant root facade secret/inheritance tests, engine race tests, and the everyday
|
||||
check. Record collection and propagation outcomes separately.
|
||||
|
||||
## Stage 12: Index CLI overlaps and validation reads
|
||||
|
||||
Roadmap candidate 4. Owner: engine `override.go`.
|
||||
|
||||
1. Retain input order and the duplicate seen map. Replace the prior-accepted
|
||||
overlap scan with earliest intersecting trie lookup using original override
|
||||
indices. Duplicate diagnostics continue preceding overlap checks.
|
||||
2. Insert exactly where `pathAccepted[index] = true` occurs today: after path,
|
||||
overlap, version, and directive checks, before value conversion/budgets.
|
||||
A later bad value still influences subsequent overlap diagnostics. Do not
|
||||
index paths rejected earlier or omit those accepted before value failure.
|
||||
3. Reuse an operation-local mapping index for read-only base traversal during
|
||||
path validation. Preserve missing mapping ancestors, preparation-before-apply,
|
||||
CLI source order/identity, rules, and limits.
|
||||
4. Compare with baseline for disjoint/duplicate/ancestor/descendant paths,
|
||||
multiple conflicts, escapes, rejected paths, and later value failures.
|
||||
Protect diagnostic codes, paths, and first related-source selection.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Override|CLI|Provenance|Diagnostic'`
|
||||
and the everyday check. No policy changes.
|
||||
|
||||
## Stage 13: Coalesce resolution replay once with indexed ancestors
|
||||
|
||||
Roadmap candidate 7. Owners: engine `history.go`, `load.go`, `load_result.go`.
|
||||
|
||||
1. Replace group scans with ancestor lookup selecting the earliest inserted
|
||||
matching group, not the deepest. Insert only new groups; merged child paths
|
||||
are not independently indexed as groups.
|
||||
2. Retain original before/after trees and normalization precedence. Use ordered
|
||||
membership sets for reason/dependency unions, retaining first occurrence and
|
||||
canonical pointer equivalence.
|
||||
3. Prepare immutable coalesced descriptors once before publication. Explain
|
||||
reads them without mutating Changes or borrowed snapshots. Retain original
|
||||
snapshots for their other metadata/history-budget uses; node accounting is
|
||||
unchanged. No renderer or public records are cached.
|
||||
4. Differentially check independent/parent/child records, multiple ancestors,
|
||||
root, equal writes, union order, normalization, and repeated detached results.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Resolution|History|Explain|Ownership'`,
|
||||
engine race tests, and the everyday check. Full replay semantics stay intact.
|
||||
|
||||
## Stage 14: Index relevant inheritance history operations
|
||||
|
||||
Roadmap candidate 7. Owners: engine metadata, metadata cloning, inheritance history.
|
||||
|
||||
1. During final metadata preparation, index inheritance operation IDs by control
|
||||
path or transfer destination. Collect intersecting IDs for History, deduplicate,
|
||||
restore original operation order, and run existing projection logic.
|
||||
2. Preserve stored-history splitting before resolution and Previous-origin
|
||||
construction. Keep fields/history/path clones independent. A fully frozen
|
||||
ID-only index may be shared in `cloneMetadata`, like immutable evidence;
|
||||
no query builds or updates it. Zero/private unprepared metadata must still
|
||||
produce correct results (use the existing scan if no prepared index exists).
|
||||
3. Leave global `appendInheritanceExplanation` replay intact: non-intersecting
|
||||
operations can affect working state and must not be skipped with this filter.
|
||||
4. Compare indexed history to the scan for multi-scope controls, removed paths,
|
||||
ancestor queries, and query mutations/captured metadata independence.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Inheritance|Inherited|History|Metadata|Independent'`,
|
||||
engine race tests, and the everyday check.
|
||||
|
||||
## Stage 15: Reuse frozen inspection mapping lookups
|
||||
|
||||
Roadmap candidate 7. Owners: publication, inspection, document/snapshot/history helpers.
|
||||
|
||||
1. Reuse Stage 7's mapping lookup builder for immutable decoded-input, final,
|
||||
and application trees queried repeatedly by inspection. Populate all retained
|
||||
maps before return, visiting shared node identities once. Retain lookup positions
|
||||
and borrowed immutable nodes, not extra trees or Path copies.
|
||||
2. Thread read-only lookups into applicable document/snapshot and application
|
||||
origin/relevance reads. Preserve validity, shape, bounds, and absence. Read
|
||||
populated maps directly, not lazy entries methods that write on first query.
|
||||
3. Keep plain document lookup on mutable replay trees in this stage. Their
|
||||
existing query-local merge indexes are unchanged; do not reuse a frozen map
|
||||
after cloning, deletion, or entry-position changes. This avoids adding an
|
||||
invalidation protocol just to optimize the selected immutable reads.
|
||||
4. Reuse shape/history/render tests; add only missing repeated/concurrent
|
||||
read-only inspection ownership cases. Do not add a public concurrency promise.
|
||||
Record extra retained-index storage honestly; this is a lookup tradeoff,
|
||||
not a free allocation reduction. Baseline/full-tree replay remains unchanged.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Path|History|Explain|Effective|Independent|Parallel'`,
|
||||
engine race tests, and the everyday check.
|
||||
|
||||
## Stage 16: Index materialized inheritance-step membership
|
||||
|
||||
Roadmap candidate 8. Owner: engine `inheritance_origin.go`.
|
||||
|
||||
1. Keep output order and compact linked traces. Use a comparable key with three
|
||||
canonical From/To/Reference strings and one encoded ordered Locations string.
|
||||
Encode the location count and each SourceID byte length, then its bytes and
|
||||
delimited decimal line/column integers. This is collision-free, including
|
||||
empty IDs, delimiter characters, and signed coordinates. Arbitrary unescaped
|
||||
delimiter concatenation is incorrect; no hashing dependency is needed.
|
||||
2. Seed membership from existing Origin.Inheritance but retain its existing
|
||||
duplicates/order. Only newly proposed steps are deduped, as today.
|
||||
3. Format candidate pointers once; clone retained paths/locations only for newly
|
||||
accepted steps. Keep contributor traversal and transfer direction intact.
|
||||
4. Compare chains, shared contributors, different location/order steps, existing
|
||||
duplicates, escaped/numeric paths, and returned-record mutation to baseline.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Inheritance|Inherited|Metadata|Provenance|History'`
|
||||
and the everyday check. Complex contributor-trace equality stays unchanged.
|
||||
|
||||
## Stage 17: Index simple resolution and origin membership
|
||||
|
||||
Roadmap candidate 8. Owners: engine `resolution.go` and `load_metadata.go`.
|
||||
|
||||
1. Maintain lazily initialized first-occurrence reason/dependency sets on
|
||||
resolution records. Dependencies use canonical pointer equality; retained
|
||||
slices and callback validation/order/nil behavior remain unchanged.
|
||||
2. Use exact Location membership in `originContainedBy`, retaining Layer/
|
||||
Operation and contributor-empty checks. Use SourceID membership in
|
||||
`originRepresentedByChange`, which has a different source-coverage predicate.
|
||||
Do not conflate these equality rules.
|
||||
3. Leave complex contributor scans and `sameInheritanceTrace` intact. Their
|
||||
concrete segment/location equality cannot be replaced by pointer identity
|
||||
or canonical spelling. Sets are phase-local, not exported record fields.
|
||||
4. Reuse existing provenance tests; cover duplicate unions, equal source IDs
|
||||
with differing locations, and location coverage with contributor mismatch
|
||||
only where protection is missing.
|
||||
|
||||
Validate: `go test ./internal/engine -run 'Resolution|Provenance|Overlay|Override|Inheritance|History'`
|
||||
and the everyday check. Small lists and outputs preserve existing semantics.
|
||||
|
||||
## Stage 18: Review the completed result and record outcomes
|
||||
|
||||
1. Review the diff from baseline. Map all nine candidates to selected implemented
|
||||
changes and expressly deferred portions. Remove dead helpers/imports/state;
|
||||
keep useful small equivalence tests, no alternate production engines.
|
||||
2. Run `./scripts/check.sh` and `go test -race ./...`. Verify public/import
|
||||
boundaries, examples, independent loads, shapes, presence, history, redaction,
|
||||
and complete-on-return behavior through their existing tests.
|
||||
3. Record algorithmic before/after work, lifetime/storage tradeoffs, revisions,
|
||||
actual commands/results, and unmeasured claims in an evidence subsection here.
|
||||
Optional probes may reuse existing startup/assembly/underlay/inheritance
|
||||
benchmarks and small record/override/dependency/query fixtures. Measurements
|
||||
are not prerequisites; timing claims await a representative host.
|
||||
4. Update stage and roadmap status accurately. Update focused internal docs
|
||||
only where they describe changed implemented mechanics. Keep public contracts
|
||||
and policy language unchanged. Do not retire other historical records or
|
||||
roadmaps as incidental cleanup.
|
||||
5. Review links/whitespace/staging, commit the completed unit, and report outcomes,
|
||||
checks, remaining deferred experiments, and workspace status. No release or
|
||||
downstream bump is included.
|
||||
|
||||
Done: selected changes preserve behavior, remain proportionate/maintainable,
|
||||
pass validation, and distinguish algorithmic expectations from measured results.
|
||||
No public performance guarantee is created.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None required for the selected scope. Algorithm, ownership, relation, ordering,
|
||||
and scope choices above are resolved. Expressly deferred experiments require
|
||||
separate design/evidence and do not block this sequence.
|
||||
|
||||
@@ -28,6 +28,26 @@ themselves grow substantially. An output-sensitive algorithm cannot avoid
|
||||
producing the output required by the existing contract. Expected map lookup
|
||||
costs and path processing costs also qualify any proposed linear bound.
|
||||
|
||||
## Target state and selected scope
|
||||
|
||||
The implementation target is the same public configuration model with less
|
||||
avoidable auxiliary work: presence-only queries do not materialize provenance;
|
||||
path comparisons and sorts avoid repeated formatting; resolution coverage,
|
||||
override overlaps, and sensitivity propagation use local path indexes;
|
||||
classification collects paths directly; and frozen inspection reuses prepared
|
||||
resolution/inheritance lookup data. Inheritance detection does not construct
|
||||
semantic paths merely to detect a keyword. Ordered provenance collections use
|
||||
membership indexes where their equality rules are straightforward.
|
||||
|
||||
The [implementation plan](implementation.md) selects bounded revisions from
|
||||
all nine candidates below. Whole-tree explanation replay remains in place;
|
||||
branch-local replay, changing the public metadata-copy handoff, global schema
|
||||
caching, and indexing complex contributor trace equality remain later
|
||||
experiments. These have larger ownership, memory, or equivalence risks than the
|
||||
selected changes. No new consumer-facing complexity bound or performance
|
||||
threshold is part of the target. The candidate descriptions retain the broader
|
||||
audit context; the plan owns the selected implementation details and sequence.
|
||||
|
||||
## Candidates
|
||||
|
||||
### 1. Avoid materializing provenance for presence-only queries
|
||||
@@ -67,9 +87,9 @@ Many nested scans below repeatedly invoke it. Sorting comparators also repeatedl
|
||||
format paths, making formatting/allocation work proportional to comparisons
|
||||
rather than items. `Lookup` formats the same query for multiple lookups.
|
||||
|
||||
First reuse an already formatted pointer within a function or decorate sortable
|
||||
items with a pointer once. Consider an allocation-free containment comparison
|
||||
over token spellings as a separate experiment. Complexity remains proportional
|
||||
Reusing an already formatted pointer within a function and decorating sortable
|
||||
items with a pointer once avoid repeated formatting. Allocation-free containment
|
||||
comparison over token spellings is also in the selected scope. Cost remains proportional
|
||||
to path length, but repeated string allocations can disappear.
|
||||
|
||||
Containment currently compares canonical pointer spellings, while metadata
|
||||
@@ -203,11 +223,11 @@ linearly scans each mapping on its path; querying every key in a wide mapping
|
||||
can therefore add quadratic lookup work. These costs compound across queries,
|
||||
even if each query asks about a small unrelated leaf.
|
||||
|
||||
First consider preparing immutable coalesced replay descriptors once when an
|
||||
inspection is constructed, and indexing relevant inheritance operations and
|
||||
frozen-tree lookups. Coalescing can use an ancestor index rather than a group
|
||||
scan. A later, separate experiment could replay only the queried branch and its
|
||||
necessary dependencies instead of cloning whole trees.
|
||||
The selected target prepares immutable coalesced replay descriptors once when an
|
||||
inspection is constructed and indexes relevant inheritance history operations
|
||||
and frozen-tree lookups. Coalescing uses ancestor lookup rather than a group
|
||||
scan. Replaying only the queried branch and its necessary dependencies remains
|
||||
a deferred experiment; whole-tree replay remains in the selected target.
|
||||
|
||||
Preserve the first covering coalesced group, ordered reason/dependency unions,
|
||||
normalization precedence, chronology, intermediate absence/replacement, typed
|
||||
@@ -274,30 +294,18 @@ to change scope rules, traversal ordering during expansion, or resource budgets.
|
||||
| Public facade and detached records | Root-owned wrappers and explicit conversions preserve the public/private boundary. Some records are copied in the engine and again during conversion; eliminating a copy needs a clear internal ownership handoff, not public aliases or borrowed mutable records. `Result.Metadata()` also clones the complete metadata before queries; consumers repeatedly obtaining it pay repeated full-copy costs. Treat redesign of that private handoff as a separate, lower-priority retained-memory/ownership experiment. |
|
||||
| Effective YAML, diagnostics, examples, and release/development tooling | Deterministic rendering and diagnostics require ordering and output-sized work; path comparator allocation is covered above. Safe snapshots and YAML adaptation allocate separate trees. Maintained consumer examples and check tooling are not production library hot paths; no gate or tooling changes proposed. ReleaseKit internals are outside this repository audit. |
|
||||
|
||||
## Recommended follow-up
|
||||
## Acceptance and boundaries
|
||||
|
||||
Start with candidate 1 or 9 as a small, reviewable optimization, then candidate
|
||||
2's local formatting reuse and candidate 5's direct classification traversal.
|
||||
These avoid work without demanding new architectural machinery. Next address
|
||||
candidate 3 for many recorded changes and candidate 6 for large dependency
|
||||
graphs. Candidates 4, 7, and 8 are useful follow-ups for consumers with many
|
||||
overrides, inspection queries, or inherited contributions.
|
||||
The selected revisions preserve the existing [configuration contract](../config.md)
|
||||
and [architecture policy](../policy/architecture.md): complete load results,
|
||||
effective versus historical path shapes, provenance, ownership, presence,
|
||||
secret isolation, and synchronous completion remain unchanged. New caps,
|
||||
input restrictions, composition rules, or performance promises are not part of
|
||||
this work. The plan owns implementation sequencing, validation, and evidence.
|
||||
|
||||
This is a prioritized backlog, not a staged implementation plan or a requirement
|
||||
to implement every candidate. Before each production change, confirm the proposed
|
||||
algorithm against the existing [configuration contract](../config.md), relevant
|
||||
tests, and [architecture policy](../policy/architecture.md). Preserve complete
|
||||
load results, effective versus historical path shapes, provenance, ownership,
|
||||
presence, secret isolation, and synchronous completion. Do not add caps, reject
|
||||
previously valid inputs, change composition rules, or create performance promises
|
||||
to simplify an optimization.
|
||||
|
||||
For a selected change, add only missing behavioral regressions, run the relevant
|
||||
package tests and everyday [development check](../development.md), and use race
|
||||
checks where ownership/shared state changes warrant them. Follow-up measurements
|
||||
can reuse existing startup, composition, underlay, inheritance, and history
|
||||
benchmarks, with targeted fixtures for record count, disjoint overrides,
|
||||
dependency chains, and repeated queries where coverage is missing. Prefer
|
||||
allocations and bytes on the busy host; defer CPU improvement claims until
|
||||
timing is representative. Benchmarks help decide whether the implementation's
|
||||
complexity is worthwhile, but are not new release gates or test thresholds.
|
||||
Success is removal of the identified redundant work and broad pairwise scans
|
||||
without disproportionate machinery or semantic regressions. Output-sized work,
|
||||
deterministic ordering, and required ownership copies remain legitimate costs.
|
||||
Benchmarks may inform the tradeoff, especially allocations on the busy host,
|
||||
but are not new release gates or test thresholds. Unmeasured improvements
|
||||
remain algorithmic expectations rather than quantified runtime claims.
|
||||
|
||||
Reference in New Issue
Block a user