Skip to content

Fix Metrics Collector full-snapshot persistence budgets - #68628

Merged
pelikhan merged 1 commit into
mainfrom
pelikhan-metrics-snapshot-persistence
Oct 14, 2026
Merged

pelikhan merged 1 commit into
mainfrom
pelikhan-metrics-snapshot-persistence

Conversation

@pelikhan

Copy link
Copy Markdown
Collaborator

Summary

Fix the Metrics Collector persistence failure from run 38502082778. Collection and freshness checks succeeded, but each complete 344-workflow snapshot was 447189 bytes against the implicit 102400-byte file cap; compacting still produces 299336 bytes, and the separate 128KiB patch cap was also insufficient.

  • Set explicit 512KiB per-file and 1MiB patch budgets without dropping workflows, fields, supplemental JSON, or changing consumer paths/schema.
  • Add read-only repo-memory validation before artifact upload and again before commit/push: fresh, nonempty, byte-identical dated/latest snapshots; measured two-copy patch budget; upload-wide 16MiB/100-file budget; valid 30-day dated history.
  • Add trusted memoryPhase metadata (baseline, upload, push) so upload-only retention checks do not falsely require deleting historical backing-branch files.
  • Replace checkout-mtime cleanup guidance with UTC filename-based upload pruning; regenerate the normal lock and add serialized-size/runtime regression tests.

Validation

  • Actual private-evidence bootstrap diff: 927158 raw bytes / 926810 charged net bytes. Two-copy replacement: 928446 raw / 924860 net. Both fit 1048576 without the runtime's 20% allowance (at least 120130 raw bytes of headroom).
  • Five focused JavaScript suites: 234 tests passed; final contract suite: 34 tests passed, including decoded emitted validator identity, configured budgets, ordering, and upload suppression condition.
  • JavaScript typecheck, make fmt-cjs, make lint-cjs, and final make agent-report-progress passed. Full make recompile: 344/344 workflows compiled; only this workflow's generated lock is published. Broad hooks and test markers ran in independent private snapshots/owned temp directories.
  • Current-CLI dry-run emitted a diagnostic lock and passed source/model checks and shellcheck, but its overall gate remains blocked by the added-validator safe-update review warning. No --approve, warning suppression, dispatch, or rerun.
  • Optional scans: poutine reports zero findings; zizmor reports eight Low findings matching the unchanged baseline. Actionlint reports existing concurrency.queue incompatibilities and dry-run-only removed AIC-output references/if: false; these are not claimed as passing checks.

Security review

Exactly one retained read-only security reviewer reviewed authored source, reachable runtime changes, tests, and both normal/dry-run locks. All ten code/normal-lock publication safety questions passed; no confirmed vulnerabilities found. The new validator payload SHA-256 is 7f0b7ce63037fdf31ef02491a4fac4e08a50eca59d5366e6c10bff4d120ab6f2 and matches all encoded/embedded instances. No secrets, recipients, action/container pins, MCP inventory, permissions, firewall, or threat-detection controls changed. Validator subprocess token exclusions, timeout, and mutation rejection remain intact. This review permits patch publication, not live execution, and does not clear dry-run/scanner warnings.

Retention boundary

The current upload retains at most 30 dated daily snapshots plus latest and accounts for all eligible supplemental JSON. Repo-memory overlays uploaded files; omitted older snapshots remain on the backing branch and in Git history. This fix deliberately adds neither generic deletion support nor a privileged branch-cleanup operation. Raw run evidence and diagnostic dry-run locks remain private and are not committed.

Couple the file, two-copy patch, and upload budgets; validate complete daily/latest snapshots before upload and push. Preserve backing-branch history with trusted validation phase metadata and bound uploaded daily history by its UTC filename.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review October 14, 2026 14:28
Copilot AI balanced review requested due to automatic review settings October 14, 2026 14:28
@pelikhan
pelikhan merged commit 60b76b5 into main Oct 14, 2026
36 checks passed
@pelikhan
pelikhan deleted the pelikhan-metrics-snapshot-persistence branch October 14, 2026 14:28
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

✅ Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

Design Decision Gate 🏗️

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Design Decision Gate 🏗️ · opus50 · 14.7 AIC · ⌖ 40.2 AIC · ◇ 48.7 AIC · ⊞ 1.8K · ◷

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

✅ Ponytail Reviewer completed successfully!

Ponytail Reviewer

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Ponytail Reviewer · gpt56 · 9.52 AIC · ⌖ 5.21 AIC · ⊞ 14.2K · ◷

Generated by Ponytail Reviewer for #68628

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

✅ Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Test Quality Sentinel · haiku45 · 5.09 AIC · ⌖ 7.52 AIC · ◇ 2.53 AIC · ⊞ 8.8K · ◷

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation is consistent across source, runtime, tests, documentation, and generated output with no unresolved defects found.

0 open findings

What changed in this PR

Fixes Metrics Collector persistence limits while adding phase-aware, read-only repo-memory validation.

Changes:

  • Raises snapshot and patch budgets for complete metrics data.
  • Adds baseline/upload/push validation phases and retention checks.
  • Adds regression coverage and updates generated workflow/docs.

No confirmed security regressions found; the referenced run confirms the prior 447,189-byte file-cap failure, and generated validator copies match the source and manifest hash.

File Description
.github/​workflows/​metrics-collector.md Defines budgets, validation, and UTC retention pruning.
.github/​workflows/​metrics-collector.lock.yml Regenerates the compiled workflow.
actions/​setup/​js/​memory_custom_validation.cjs Exposes trusted validation-phase metadata.
actions/​setup/​js/​memory_custom_validation.test.cjs Tests phase values and compatibility default.
actions/​setup/​js/​validate_memory_step.cjs Assigns baseline and upload phases.
actions/​setup/​js/​push_repo_memory.cjs Assigns push phase before commit and retry.
actions/​setup/​js/​metrics_collector_workflow.test.cjs Covers budgets, retention, artifacts, and runtime wiring.
docs/​src/​content/​docs/​reference/​repo-memory.md Documents memoryPhase behavior.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

Peek at saved memory (pr-code-quality-reviewer)
reviewed_at: 2026-10-14T14:32:01.920+00:00
review_event: REQUEST_CHANGES
top_themes:
  - baseline retention deadlock
  - repo-memory branch cleanup gap
files_reviewed:
  - .github/workflows/metrics-collector.md
  - actions/setup/js/memory_custom_validation.cjs
  - actions/setup/js/validate_memory_step.cjs
  - actions/setup/js/push_repo_memory.cjs
  - actions/setup/js/metrics_collector_workflow.test.cjs
comment_count: 1

Note

This comment is managed by comment memory.

Expand the saved memory block to view or edit the persistent context for this thread.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 29.3 AIC · ⌖ 5.97 AIC · ⊞ 19.8K · ◷
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocking issue: the new retention/phase split makes the Metrics Collector stop persisting snapshots once the repo-memory branch contains more than 30 days of history.

### Why I am requesting changes `baseline` still runs the 30-day upload-window check against the full backing-branch checkout, but this workflow deliberately does not delete omitted daily snapshots from that branch. After enough daily runs, baseline validation starts failing before the agent runs, and `push_repo_memory` cannot repair the state because it stages uploaded files only, not deletions. That turns repo-memory persistence into a permanent warn-and-skip-artifact path instead of a temporary retention guard.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 29.3 AIC · ⌖ 5.97 AIC · ⊞ 19.8K
Comment /review to run again

if (memoryPhase === "push") return;
const cutoff = new Date(`${day}T00:00:00Z`);
cutoff.setUTCDate(cutoff.getUTCDate() - 29);
const oldestDay = cutoff.toISOString().slice(0, 10);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This phase split will deadlock metrics persistence after the branch ages past 30 days because baseline still validates the full backing-branch checkout against the upload window while push_repo_memory never stages deletions for omitted snapshots.

💡 Why this blocks merge On day 31, the branch still contains older `metrics/daily/*.json` files, so `validateRepoMemoryBaseline(... phase: "baseline")` starts failing with the 30-day error before the agent runs. The workflow cannot repair that state: the cleanup step only prunes the upload directory, and `push_repo_memory` stages only `filesToCopy`, so historical files that were omitted from the artifact remain on the branch forever. That turns this into a permanent warn-and-skip-artifact condition for every later run.

Please either commit deletions for pruned snapshots, or exempt baseline from the upload-retention check so the collector can keep persisting new data.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /tdd and /diagnosing-bugs — this is a well-instrumented bug fix with measured evidence and comprehensive regression coverage; approving with one minor test-robustness suggestion.

📋 Key Themes & Highlights

Key Themes

  • Root cause properly addressed, not just symptoms (/diagnosing-bugs): the fix raises max-file-size/max-patch-size to measured values (512KiB/1MiB) and adds a validation.script gate that enforces those budgets before upload/push, rather than just bumping numbers and hoping. The memoryPhase metadata (baseline/upload/push) correctly distinguishes "this run's upload directory" from "the full backing-branch overlay," so retention checks don't falsely fail when the push phase sees omitted historical files.
  • Strong regression coverage (/tdd): the new 355-line metrics_collector_workflow.test.cjs suite exercises the gate against the real embedded script extracted from the markdown (not a reimplementation), checks budget consistency between the frontmatter, the inline script, and the compiled lock file, and drives the real push_repo_memory.cjs main() against a real git repo with mocked network/push effects. This is exactly the kind of "test the actual contract, not a mock of it" approach that prevents silent drift between doc/script/lock.
  • One minor robustness gap: the regex-based extraction of the validation script from the markdown source (metrics_collector_workflow.test.cjs:18) has no guard — a future doc edit that shifts indentation would produce an unhelpful null-deref instead of a clear failure message. Flagged inline.

Positive Highlights

  • ✅ Clear separation between upload-time retention enforcement (30-day pruning, artifact count/size) and push-time integrity checks (byte-identical latest/daily pair), gated cleanly via memoryPhase.
  • ✅ Correctly replaces find -mtime cleanup (broken by checkout mtime resets) with UTC filename-based pruning — directly addresses the stated root cause.
  • ✅ Case-insensitive but case-rejecting filename validation (/^\d{4}-\d{2}-\d{2}\.json$/i match + explicit lowercase-only enforcement) is a nice defense against silently accepting 2026-10-13.JSON as a different file than the canonical lowercase one.
  • ✅ Docs updated in lockstep with the new memoryPhase global and its semantics.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 198.7 AIC · ⌖ 14.7 AIC · ⊞ 10.3K
Comment /matt to run again

const frontmatter = source.split("---")[1];
const maxFileBytes = Number(frontmatter.match(/max-file-size: (\d+)/)[1]);
const maxPatchBytes = Number(frontmatter.match(/max-patch-size: (\d+)/)[1]);
const gate = source.match(/ validation:\n script: \|\n([\s\S]*?)\npre-agent-steps:/)[1].replace(/^ /gm, "");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] This contract test parses the embedded validation script straight out of metrics-collector.md via .match(...)[1] with no guard. If the markdown indentation or the pre-agent-steps: anchor ever shifts even slightly during a future edit, this throws a bare Cannot read properties of null (reading '1') instead of a message pointing at the real cause (doc/validator drift).

💡 Suggested improvement

Guard each extraction with an explicit assertion so failures are self-diagnosing:

const gateMatch = source.match(/    validation:\n      script: \|\n([\s\S]*?)\npre-agent-steps:/);
if (!gateMatch) {
  throw new Error("Could not locate validation.script block in metrics-collector.md - update this regex if the doc format changed");
}
const gate = gateMatch[1].replace(/^        /gm, "");

Same applies to the maxFileBytes/maxPatchBytes/prune/example extractions a few lines above/below - a null-deref here is much harder to debug in CI than a clear "regex no longer matches" error, especially since this suite is explicitly a drift-detection contract test.

@copilot please address this.

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.

2 participants