From 1b00e1b67c3fe7b6b396d28ecf6d8793843b3840 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 06:49:51 +0200 Subject: [PATCH 01/24] feat: evolve bounded recipes over public tracker histories --- .agents/pm/chores/pm-rl-hncb.toon | 5 +- .agents/pm/features/pm-rl-meta.toon | 54 +++ .agents/pm/features/pm-rl-whrd.toon | 5 +- .agents/pm/history/pm-rl-bi4v.jsonl | 3 + .agents/pm/history/pm-rl-hncb.jsonl | 3 + .agents/pm/history/pm-rl-meta.jsonl | 23 ++ .agents/pm/history/pm-rl-mjo5.jsonl | 3 + .agents/pm/history/pm-rl-whrd.jsonl | 3 + .agents/pm/tasks/pm-rl-bi4v.toon | 5 +- .agents/pm/tasks/pm-rl-mjo5.toon | 5 +- README.md | 21 +- RECURSIVE_TRAINING.md | 10 + dataset.ts | 165 ++++++++ docs/durable-systemone-validation.md | 2 +- docs/meta-live-evidence.json | 591 +++++++++++++++++++++++++++ docs/meta-recursive.md | 134 ++++++ examples/meta-approval.md | 24 ++ examples/meta-trackers.json | 71 ++++ index.ts | 58 +++ loop.ts | 16 + manifest.json | 2 +- meta.ts | 267 ++++++++++++ package.json | 23 +- recipe.ts | 70 ++++ scripts/live-meta.ts | 86 ++++ scripts/live-watchdog.ts | 4 +- test/dataset.test.ts | 121 ++++++ test/fixtures/meta-controller.ts | 15 + test/fixtures/meta-workspace.ts | 63 +++ test/fixtures/tracker-histories.json | 6 + test/meta.test.ts | 312 ++++++++++++++ test/recipe.test.ts | 49 +++ tracker-environment.ts | 98 +++++ 33 files changed, 2299 insertions(+), 18 deletions(-) create mode 100644 .agents/pm/features/pm-rl-meta.toon create mode 100644 .agents/pm/history/pm-rl-meta.jsonl create mode 100644 dataset.ts create mode 100644 docs/meta-live-evidence.json create mode 100644 docs/meta-recursive.md create mode 100644 examples/meta-approval.md create mode 100644 examples/meta-trackers.json create mode 100644 meta.ts create mode 100644 recipe.ts create mode 100644 scripts/live-meta.ts create mode 100644 test/dataset.test.ts create mode 100644 test/fixtures/meta-controller.ts create mode 100644 test/fixtures/meta-workspace.ts create mode 100644 test/fixtures/tracker-histories.json create mode 100644 test/meta.test.ts create mode 100644 test/recipe.test.ts create mode 100644 tracker-environment.ts diff --git a/.agents/pm/chores/pm-rl-hncb.toon b/.agents/pm/chores/pm-rl-hncb.toon index 6b0fdac3..5d988472 100644 --- a/.agents/pm/chores/pm-rl-hncb.toon +++ b/.agents/pm/chores/pm-rl-hncb.toon @@ -6,12 +6,12 @@ status: in_progress priority: 1 tags: [] created_at: "2026-09-26T19:59:42.997Z" -updated_at: "2026-10-11T09:55:45.115Z" +updated_at: "2026-10-18T03:01:17.393Z" author: codex acceptance_criteria: "Package and lockfile pin published PM CLI 2026.10.4; full direct release:check and strict tracker health pass on installed dependencies; packed npm and Bun extension acceptance with CLI 2026.10.4 is measured; PR links this item and records independent review, publication and recursive-training limitations." parent: pm-rl-apvf actual_result: "Self-syncing dependency/provenance contracts verified. Actual #67 dependency delta and restored branch each pass complete npm/Bun release gates: 444/444 tests, zero failures/skips/cancellations, all four unchanged 100% measures across24 authored sources. Restored npm uses clean HOME and disabled global/system Git configuration. Behavioral provenance-only revert fails0/1 after rebuild; prepare behavior-only revert fails0/2; restored prepare11/11. Exact source-head Node22/26 CI also444/444 and100% all four. No pins downgraded, release, merge or item closure. PR69; manual review remains separate." -comments[34]{created_at,author,text}: +comments[35]{created_at,author,text}: "2026-09-28T06:51:05.996Z",claude-hub,"2026-09-28: pinned pm-ops 2026.9.28 and re-copied its templates/prepare-merge-driver.ts in 29e11d7 (pm-ops#124: the omit-dev skip now checks every Node resolution path for an incomplete hoisted pm-ops). release:check and changelog:check pass on this branch. Acceptance criteria and the launcher link note now name pm-ops 2026.9.28; the dated 2026.9.26 notes above stay as historical results." "2026-10-02T18:22:43.959Z",pi-land-a,"Merge-readiness verification pass by pi-land-a (fleet PR landing session): exact head 9fe6606 is mergeable and CLEAN against origin/main; Node 22/26, CodeQL CI green; all five review threads resolved; re-requested the bot review window because CodeRabbit's prior full-review attempt on this head failed with an internal error (issuecomment-5891308945) and Greptile/Gemini are not active on this repository." "2026-10-02T18:52:29.433Z",pi-land-a,"Cubic review (new head 9a2b201) findings on this candidate: (1) valid - the tracked bun.lock still resolved @unbrained/pm-cli, pm-changelog and pm-ops at 2026.8.1; regenerated with bun 1.3.5 so it now resolves the exact pins 2026.9.29/2026.9.25/2026.9.28. (2) valid - the v2026.9.28 release link was mislabeled 'used by this candidate'; relabeled as the earlier heads' SDK, superseded by 2026.9.29. Refused with reasons in their threads: the lstatSync/require.resolve.paths launcher probes are the byte-identical published pm-ops template (upstream pm-ops issue filed), and the npm pack final-line parse uses --ignore-scripts so prepare output cannot follow the archive name, with an exact-regex assertion that fails loudly otherwise. Full npm run release:check after the changes passed 329/329 with 100/100/100/100 measured coverage over 20 sources and zero production audit findings." @@ -46,6 +46,7 @@ comments[34]{created_at,author,text}: "2026-10-11T09:28:15.478Z",codex-agent,"Orchestrator handoff after the Codex forecast crossed the user limit: further CLI model requests are stopped while the running clean-Git-identity gate continues. Actual #67 overlay npm and Bun complete gates both passed 444/444, zero skips, all four 100% measures across 24 configured sources; real packed CLI loops measured 13081.08ms and 13212.48ms under the unchanged 20000ms guard. Package and lock files are restored to the immutable rebased main state. Orchestrator will verify the active npm identity result, run the remaining baseline Bun gate, commit all paired tracker evidence and release ownership without closing the item." "2026-10-11T09:45:32.898Z",codex-agent,"Orchestrator verified complete restored clean-HOME/Git-identity npm release:check: exit 0, 444/444 tests, zero failures/skips, all four 100% measures across 24 authored sources and every later release stage. Baseline Bun is running directly; both actual #67 overlay npm/Bun receipts already pass 444/444. Original job logs locate the 99.67% function and 99.87% branch gaps in index.ts: missing source_kind in deep reads falsely rejected benchmark provenance before leaderboard contamination/environment paths could run. Full Benchmark reads restore those paths; additional child-readiness/SIGKILL regressions cover launcher changes without weakening deadlines or assertions." "2026-10-11T09:55:43.173Z",codex-agent,"Final orchestrator verification: root baseline bun run release:check exited0 in1058.761s,444/444 tests, zero failures/skips/cancellations,24 sources at100% lines/branches/functions/statements, production audit0, packing and final changelog check passed. Alongside baseline clean-HOME/Git-identity npm and actual #67 npm/Bun receipts, all four required full local gates now pass. Package/lock restored byte-exact to rebased source head38ba808; #65 receipt-recovery and its coverage entry retained. Regression tests fail with only old behavior restored and dist rebuilt, as recorded above. Linked PM parser/ranking2/2 and ready-child1/1 pass; inherited PM_PATH init collision remains an existing wrapper gap, not a source-test failure. Claims are released, items remain open; no merge or publication." + "2026-10-18T03:01:16.233Z",codex-agent,"Audit: STALE / NOT MET literally at current main: acceptance names PM CLI/SDK 2026.10.4, while package and lock now pin 2026.10.13. Earlier certification and merged self-syncing dependency work record their own exact-head evidence, but they cannot certify the current dependency identity as 2026.10.4. Missing: orchestrator disposition of the obsolete version-specific item, rather than another stale certification run. No dependency changes or certification work performed; leave open." notes[9]{created_at,author,text}: "2026-09-26T20:06:25.026Z",codex,"Initial pm test linked release gate failed because the default schema sandbox injected PM_PATH into npm tests that initialize their own temporary trackers; direct release:check reached a real canonical-launcher mismatch with pm-ops 2026.9.26. Updated the launcher from the installed canonical template. Both observations are distinct; revalidation follows." "2026-09-26T20:15:33.662Z",codex,"2026-09-26: Direct npm run release:check on installed PM CLI/SDK 2026.9.26, pm-ops 2026.9.26 and pm-changelog 2026.9.25 passed 329/329 tests, 0 failures, 100.00% statements/lines/branches/functions over 20 authored source files, 136/136 documented declarations, zero duplication and zero npm production vulnerabilities. Packed pm-rl tarball installed and imported under npm/Node and Bun 1.3.5. PM linked bandit acceptance passed 14/14. Strict PM health ok=true with an existing provenance-value warning. Full linked npm test context limitation is upstream pm-cli#1318; direct full gate is the valid package result." diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon new file mode 100644 index 00000000..2a6a5b36 --- /dev/null +++ b/.agents/pm/features/pm-rl-meta.toon @@ -0,0 +1,54 @@ +id: pm-rl-meta +title: Improve bounded training recipes over public tracker histories +description: "Content-addressed bounded recipes, deterministic outer search, isolated repository splits and durable shared-budget inner loops with honest final-test reporting." +type: Feature +status: in_progress +priority: 2 +tags: [] +created_at: "2026-10-18T03:01:18.320Z" +updated_at: "2026-10-18T04:49:36.187Z" +assignee: codex-agent +claim_principal: codex-agent +author: codex-agent +acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." +parent: pm-rl-apvf +comments[9]{created_at,author,text}: + "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." + "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." + "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." + "2026-10-18T03:43:18.600Z",codex-agent,"Live acceptance PASS: npm run test:live completed two meta-generations, K=2, over 25 public MIT repositories (15 train, 5 meta-validation, 5 final-test); one verified empty source omitted. Dataset a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c contains 1023 train, 145 inner held-out, 214 meta-validation, 385 final-test examples (1767 total). Initial recipe b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae: learning_rate=0.25, steps=2, batch=128, temperature=1, reward weights=1/0, selection=all, curriculum=forward. Generation 1 candidates 800886e9f4cd and 45113586500f; generation 2 candidates 4a48567235f1 and 55539a90ca05. Every resulting policy scored 107/214=0.5 on meta-validation: gain 0, lower confidence gain bound -0.21778781183411927, refusal no_statistical_improvement. Confidence 0.95 allocated across four comparisons gives 0.9875 each; effect threshold 0.01 and minimum samples 10 unchanged. No recipe promoted: inner promotion retained seed policies. Final untouched test before/after 198/385=0.5142857142857142. Dataset build plus controller 574489.248227 ms; parent watchdog unchanged at 15 minutes. Complete public source commits, recipes and verdicts: docs/meta-live-evidence.json. No improvement claim." + "2026-10-18T03:47:10.210Z",codex-agent,"Further real-controller regressions PASS 3/3: a physical outer-controller SIGKILL adopts the committed initial fit and original settled reservation; a high-signal synthetic fixture promotes a statistically better recipe and uses it as the next meta-generation incumbent; one shared Decision refuses expanded/replaced/oversubscribed budgets, including differently formatted reservation bodies. The full tracker read path remains certified. Normal local health exposes a global pm-github host-version skew (pinned 2026.10.13 versus global 2026.10.17); the isolated CI HOME/Git configuration passes strict health with only pre-existing advisory provenance debt (pm-rl-9uz4). No pin bump, telemetry configuration change or history repair performed. Linked pm test selection 1 passes 8/8; result tracking is disabled by existing project policy, so this comment retains the receipt." + "2026-10-18T03:55:07.043Z",codex-agent,"The search now receives sealed evaluator capabilities (fit, selection scores, final-test scores and dataset digest) rather than dataset readers. Dataset coordinates and all example loading stay in tracker-environment.ts; the proposer receives a fresh recipe-only request object. Terminal replay still succeeds with inner and final files unavailable, and the final-test callback runs after all promotion receipts. Unknown recipe knobs are rejected against the declared domain keys. The CLI optional seed/proposer defaults and camel-cased tracker option are fixed; direct real-tracker CLI and synthetic live-entry regressions pass 2/2. The physical-kill/promotion/shared-budget trio also passes 3/3 through the linked PM harness; result recording remains disabled by policy." + "2026-10-18T03:58:51.495Z",codex-agent,"Final real-data acceptance after evaluator capability isolation passes again: the complete dataset manifest and policy/gate/final-test report are byte-equivalent as JSON to the first successful run (same 25 eligible public repos, 1767 examples, four refused recipes, gain 0 with lower bound -0.21778781183411927, final-test 198/385 before and after). No statistical or feature tuning followed final-test exposure. The governing programme now binds the canonical approval item identity as well as its spec digest; an identical replacement Decision cannot switch budgets during resume. Full npm and Bun release gates follow with unchanged thresholds and CI identity isolation." + "2026-10-18T04:05:27.268Z",codex-agent,"Self-review tightened the evaluator boundary before the final gates: outer accounting and proposal recovery now perform certified Decision metadata listings with bodies excluded, then open only the stable reservation namespace or exact proposal-attempt record. They no longer request every tracker body, which could include inner environment/seed datasets. Reservation discovery uses stable item identities, so a title edit cannot hide an allocation. Regression cases include unrelated prose, copied envelopes, independent approvals and replacement Decisions with identical specs. The first release-gate attempt was deliberately interrupted for this correction; no passing full-gate result is claimed from it." + "2026-10-18T04:49:36.187Z",codex-agent,"Final ledger regressions pass 3/3: interrupted atomic reservations retain one charge, independent programmes cannot oversubscribe, and approval replacement or copied/corrupt reservation tuples are refused. Programme identity, canonical approval ID, recipe plan and exact charge vector are bound into the durable receipt. Full npm and Bun release gates now run against the frozen implementation; thresholds and legacy deadlines remain unchanged." +files[18]{path,scope}: + dataset.ts,project + examples/meta-approval.md,project + examples/meta-trackers.json,project + index.ts,project + loop.ts,project + manifest.json,project + meta.ts,project + package.json,project + recipe.ts,project + scripts/live-meta.ts,project + scripts/live-watchdog.ts,project + test/dataset.test.ts,project + test/fixtures/meta-controller.ts,project + test/fixtures/meta-workspace.ts,project + test/fixtures/tracker-histories.json,project + test/meta.test.ts,project + test/recipe.test.ts,project + tracker-environment.ts,project +tests[2]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: + node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop + "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop +docs[6]{path,scope}: + docs/durable-systemone-validation.md,project + docs/meta-live-evidence.json,project + docs/meta-recursive.md,project + examples/meta-approval.md,project + README.md,project + RECURSIVE_TRAINING.md,project +body: "" diff --git a/.agents/pm/features/pm-rl-whrd.toon b/.agents/pm/features/pm-rl-whrd.toon index 58f4814a..f43e1104 100644 --- a/.agents/pm/features/pm-rl-whrd.toon +++ b/.agents/pm/features/pm-rl-whrd.toon @@ -6,11 +6,11 @@ status: in_progress priority: 2 tags[3]: execution,llm-adapter,recursive-training created_at: "2026-10-15T22:07:13.392Z" -updated_at: "2026-10-16T06:12:51.664Z" +updated_at: "2026-10-18T03:01:06.851Z" author: codex-agent acceptance_criteria: "Two real generations with successor collection; SIGKILL recovery, cancellation, corrupt checkpoint and limit refusals, one-launch contention; behavioural revert proofs and unchanged npm and Bun release gates." parent: pm-rl-apvf -comments[23]{created_at,author,text}: +comments[24]{created_at,author,text}: "2026-10-15T22:07:43.111Z",codex-agent,"Design: extend the existing process contract with a typed LM payload and checkpoint validator; share owner fences, atomic reservation, staged adoption, cancellation and settlement. Keep held-out examples in the controller. Bind immutable image, memory and CPU ceilings into programme and job identity; send only frozen weights, source adapter, training strings and collected rewards to a networkless non-root container. Add real recursive generations and crash/cancellation/limit/contention drills, then behavioural revert proofs and unchanged release gates." "2026-10-15T22:16:06.750Z",codex-agent,"First real Compose evidence: generation 1 checkpoint 058aa3d2c08438abd18cf0e9b455aca99ddb95492de852201c55c79a0672130d -> 37e503748a170be32e1d506997b6c0cc5c9ee256b24ab01fb49cf0564da07b4c; held-out sampled reward 0.183854, six steps, 1152 target tokens, observed wall 5567 ms, fit CPU 820 ms, peak RSS 138629120 bytes, retained staging 88930 bytes. Generation 2 collected with that promoted digest and trained -> 086f78992283cba37929321abe3961ca6132a52c332bf8a8387a52f22141cbdb; reward 0.292396, six steps, 1152 tokens, wall 5654 ms, CPU 803 ms, peak RSS 143323136 bytes, staging 92364 bytes. Both promoted through the existing gate. Real controller SIGKILL after completion before receipt commit recovered the same checkpoint and original reservation with one launch. Mid-fit cancellation retained input/events and process_cancelled. Full drills and coverage verification continue. The first linked run reached its default 120-second timeout; rerun will explicitly allow the complete integration duration." "2026-10-15T22:24:09.789Z",codex-agent,"Validated linked run: pm test pm-rl-whrd --run --progress --timeout 900 passed 8/8, zero failures/skips/cancellations/todo. Real kernel memory drill retained partial allocation evidence and daemon oom_killed=true at 201326592 bytes; the time drill began the real 1000-step fit before exceeding its 15000 ms allowance. Both refused promotion and successor collection. Two-generation execution took 54134.161 ms; independent verification/replay/status took 4470.981 ms. Canonical hashes and held-out objectives match the first measurement. Final fit resources: generation 1 wall 4297 ms, CPU 713 ms, RSS 138207232 bytes, staging 89057 bytes; generation 2 wall 4266 ms, CPU 759 ms, RSS 144183296 bytes, staging 92509 bytes; both six steps and 1152 target tokens. Daemon receipts verify memory=268435456, CPU=1, no network and non-root user. Existing Compose barrier variability is tracked in pm-rl-8nev. Revert proofs and complete release gates remain in progress." @@ -34,6 +34,7 @@ comments[23]{created_at,author,text}: "2026-10-16T04:36:54.188Z",codex-agent,"Final unchanged-allowance contention loops: Node 22.23.1 passes 20/20 and Node 26.7.0 passes 20/20, zero failures or skips; each invocation executes the real Compose contention test. Independently checked all 40 reporter logs. The new linked contention command also passes through pinned pm test --run --only-last --progress in the default schema context (1/1, exit 0). CI-style isolated HOME strict PM health with required merge drivers passes; default HOME separately reports the existing global pm-github version-skew gate failure and retained advisory findings. No global extension or history repair was performed. Next: full literal npm and Bun gates with isolated HOME/Git and executable RAM scratch trackers." "2026-10-16T05:51:23.733Z",codex-agent,"Extended CI parity: the failed GitHub job used Node 26.12.0, while initially installed Node 26 was 26.7.0. Installed the exact 26.12.0 runtime with verified download checksum. Three diagnostic original-source contention probes also passed on 26.12.0, so the historical refusal remains unconfirmed. The final synchronized test now independently passes 20/20 on each of Node 22.23.1, 26.7.0 and 26.12.0 (60/60, zero failures/skips). Re-fetched main; it remains an ancestor, so no merge is needed. Literal Bun release gate at source 91d40fc passes 590/590, zero failures/skips/cancellations, all four coverage dimensions 100% across 30 sources, 272 documented declarations, and all audit/package/changelog checks. First npm attempt retains 589/590 with only the packed CLI child reaching its unchanged 25000 ms timeout; concurrent diagnostic probes added load, so that attempt is not passing gate evidence. Serial npm retry is now running alone on exact CI Node 26.12.0." "2026-10-16T06:12:44.947Z",codex-agent,"Final local delivery at source/test commit 91d40fc: literal npm run release:check on Node 26.12.0 exits 0 with 590/590 passing, zero failed/skipped/cancelled, all four coverage dimensions 100% over all 30 sources, 272 documented declarations, and identity/audit/package/changelog checks passed. Literal bun run release:check on Node 26.7.0 and Bun 1.3.5 also exits 0 with 590/590 and the same unchanged four 100% thresholds. Packed CLI measured 10996.891 ms (npm retry) and 11086.851 ms (Bun). Preserve the first npm attempt: 589/590, sole unchanged 25000 ms packed CLI timeout; it is not passing gate evidence. Final contention loops are 20/20 each on Node 22.23.1, 26.7.0 and exact CI 26.12.0. The original CI winner refusal cannot be recovered from its log and did not reproduce; the reservation barrier invariant is proved, but the historical timeout root cause remains unconfirmed. Cleanup independently verifies zero repository Compose containers, and three owned validation images were removed after checking their exact owner label. Original history byte prefixes remain unchanged for both touched items. Main is already an ancestor; ready to push and wait for GitHub checks, without merging or resolving threads." + "2026-10-18T03:01:05.676Z",codex-agent,"Audit: MET against recorded acceptance. Merged PR #80 (b255dfac6543ab178ab2720fad1de1ba49f91dd4) supplies two real external LM generations and successor collection, SIGKILL staged-completion recovery without retraining or double charge, cancellation, corrupt checkpoint and resource refusals, and one-launch contention. docs/lm-adapter.md and test/lm-compose.test.ts retain measured evidence; feature and fixture behavioural revert proofs are recorded. Final isolated npm and Bun release gates each passed 590/590 with exact four-metric 100% coverage. No acceptance gap found in merged evidence; storage kernel enforcement remains separately tracked in pm-rl-7073. Leave open for orchestrator verification." files[20]{path,scope}: .dockerignore,project compose.ts,project diff --git a/.agents/pm/history/pm-rl-bi4v.jsonl b/.agents/pm/history/pm-rl-bi4v.jsonl index 2784695d..83b5ead2 100644 --- a/.agents/pm/history/pm-rl-bi4v.jsonl +++ b/.agents/pm/history/pm-rl-bi4v.jsonl @@ -13,3 +13,6 @@ {"hash_algorithm":"sha256","ts":"2026-10-16T00:15:13.401Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"0b7326fe7529e37d974d8e2f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-10-16T00:15:13.400Z","author":"codex-agent","text":"Latest PM-linked verification passes 1/1 with all eight boundaries, zero skips: case 206859.047 ms inside the unchanged 300000 ms test deadline. The full-gate child inheritance regression is explicitly checked at bootstrap; guard removal fails and restored isolation passes. The child also runs with the actual scratch project cwd. No authored source is excluded from coverage, and no test assertion or deadline was removed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-16T00:15:13.401Z"}],"before_hash":"694cba1e5c37e89605d4d259ab2b760253d76548efb2db6c736a6b161188f7b5","after_hash":"2a5eca0ae67cd0eaf23ac76787cb7a6fd0e4f5468be2b6e45454929058837f35","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f56328025f62c844eecd2af08b115afa0604f94ad4ca210b11afbffb79ce0f6c"} {"hash_algorithm":"sha256","ts":"2026-10-16T03:47:19.355Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"0b7326fe7529e37d974d8e2f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-10-16T03:47:19.355Z","author":"codex-agent","text":"Final verification: both complete npm and Bun release gates pass 590/590, zero skips, all four coverage dimensions 100%. All eight real HTTP crash boundaries pass within the unchanged 300-second test limit. Independent datasets execute in bounded pairs; SIGKILL children report and enforce coverage isolation; the parent still covers the complete source inventory. Removing child coverage isolation fails the runtime regression, restored execution passes. No assertion, deadline or threshold was weakened. Leave open for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-16T03:47:19.355Z"}],"before_hash":"2a5eca0ae67cd0eaf23ac76787cb7a6fd0e4f5468be2b6e45454929058837f35","after_hash":"01c27524acd16e3960b1117152121f4ddc00978405aa462e73a2a4710a8c2f94","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0c5500dafadf4a049cdc37b5a539eaef1d1cc3a6a2dcd887ce952352548bed6b"} {"hash_algorithm":"sha256","ts":"2026-10-16T03:47:23.897Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"0b7326fe7529e37d974d8e2f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-16T03:47:23.897Z"}],"before_hash":"01c27524acd16e3960b1117152121f4ddc00978405aa462e73a2a4710a8c2f94","after_hash":"53e880efbdb7414937f3b8e90ea3ef86463ae65f5db3cf7614b59e97abfd85c8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"40fef12c25c8645a9cc4bdfdc786be8ebfcb19df73ab053af60a53538e26ed37"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:10.952Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:10.952Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"53e880efbdb7414937f3b8e90ea3ef86463ae65f5db3cf7614b59e97abfd85c8","after_hash":"ed49125d86beafda1de9d7e9708676e510e38f80cd2b9c7420bebe94bde32984","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7b4972407f388c12b81017a0c56144998460256c926aeeb15bcad37174e353a6"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:13.159Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-10-18T03:01:13.159Z","author":"codex-agent","text":"Audit: MET against recorded acceptance in merged PR #80. The serial baseline measured 276105.853 ms; concurrent full runs hit the unchanged 300000 ms limit. Forked crash children inherited V8 coverage; isolated child execArgv and raw coverage output plus bounded independent pairs retain all eight real HTTP-to-PM crash boundaries. Guard-only revert fails with inherited-coverage evidence; restored focused and linked runs pass. Both full release gates passed 590/590 with all eight boundaries within 300000 ms and unchanged four-metric thresholds. No remaining acceptance gap in that evidence; leave open for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:13.159Z"}],"before_hash":"ed49125d86beafda1de9d7e9708676e510e38f80cd2b9c7420bebe94bde32984","after_hash":"1ed034779069d09b69d118e6c055fb241d3fe7a6513fa95e3f3ab14005a4ae8a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"dda92b7d900ec21fc3739286a5d26f1b73852237d839a3a7404f6416f23fe42e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:14.190Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:14.190Z"}],"before_hash":"1ed034779069d09b69d118e6c055fb241d3fe7a6513fa95e3f3ab14005a4ae8a","after_hash":"4b4c2649ed7fa28ad7e2f4ec20755e45669187cf2ca81215cc956de7fc0d7c4b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"ee845440b1866e229db080ccc94bdb28d241ce19dfeb0d6cd83ebc888d90ae7d"} diff --git a/.agents/pm/history/pm-rl-hncb.jsonl b/.agents/pm/history/pm-rl-hncb.jsonl index fe1b2f4b..ca539d08 100644 --- a/.agents/pm/history/pm-rl-hncb.jsonl +++ b/.agents/pm/history/pm-rl-hncb.jsonl @@ -100,3 +100,6 @@ {"hash_algorithm":"sha256","ts":"2026-10-11T09:55:43.173Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"57ac6300a08c2cd01dfae63f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/33","value":{"created_at":"2026-10-11T09:55:43.173Z","author":"codex-agent","text":"Final orchestrator verification: root baseline bun run release:check exited0 in1058.761s,444/444 tests, zero failures/skips/cancellations,24 sources at100% lines/branches/functions/statements, production audit0, packing and final changelog check passed. Alongside baseline clean-HOME/Git-identity npm and actual #67 npm/Bun receipts, all four required full local gates now pass. Package/lock restored byte-exact to rebased source head38ba808; #65 receipt-recovery and its coverage entry retained. Regression tests fail with only old behavior restored and dist rebuilt, as recorded above. Linked PM parser/ranking2/2 and ready-child1/1 pass; inherited PM_PATH init collision remains an existing wrapper gap, not a source-test failure. Claims are released, items remain open; no merge or publication."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-11T09:55:43.173Z"}],"before_hash":"9cd4b11774dd4a9fa611e401546d28f0322e75ee2c880c255645591dc6ae5281","after_hash":"f42d7fdcdb4af760318ec425f93a37c53eaf76fbc9f65775431de740598dee21","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"eb4e222f5fb91c5b99cbfb5a0950114344afcdea4f6a4e304dec8f1a287a8d02"} {"hash_algorithm":"sha256","ts":"2026-10-11T09:55:44.081Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"57ac6300a08c2cd01dfae63f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"remove","path":"/metadata/docs/7/note"},{"op":"replace","path":"/metadata/docs/7/path","value":"README.md"},{"op":"replace","path":"/metadata/docs/6/path","value":"https://github.com/unbraind/pm-rl/actions/runs/38125103348"},{"op":"add","path":"/metadata/docs/5/note","value":"Linked test sandbox issue"},{"op":"replace","path":"/metadata/docs/5/path","value":"https://github.com/unbraind/pm-cli/issues/1318"},{"op":"remove","path":"/metadata/docs/4/note"},{"op":"replace","path":"/metadata/docs/4/path","value":"docs/dependency-bump-validation.md"},{"op":"add","path":"/metadata/docs/3/note","value":"Full gate and real tracker packed npm/native Bun evidence"},{"op":"replace","path":"/metadata/docs/3/path","value":"docs/certification-2026.10.4.md"},{"op":"replace","path":"/metadata/docs/2/note","value":"Self-syncing dependency bump candidate"},{"op":"replace","path":"/metadata/docs/2/scope","value":"global"},{"op":"replace","path":"/metadata/docs/2/path","value":"https://github.com/unbraind/pm-rl/pull/69"},{"op":"add","path":"/metadata/docs/8","value":{"path":"RECURSIVE_TRAINING.md","scope":"project","note":"Controller scope remains open"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-11T09:55:44.081Z"}],"before_hash":"f42d7fdcdb4af760318ec425f93a37c53eaf76fbc9f65775431de740598dee21","after_hash":"a700d6e4f9341036a3d57cb9e3bef41f99efeb446077e200c9f9ab6b22187938","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"bf27faa822ad467043ed114fc2f2502dcdfa06e0b5c982204e3ac8083448684b"} {"hash_algorithm":"sha256","ts":"2026-10-11T09:55:45.115Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"57ac6300a08c2cd01dfae63f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-11T09:55:45.115Z"}],"before_hash":"a700d6e4f9341036a3d57cb9e3bef41f99efeb446077e200c9f9ab6b22187938","after_hash":"c89ac39e59198ad22528e27877941b390c615d839c533c1a7ea8aa4ca0bbf6b6","item_hash_version":3,"message":"Verification complete; keep item open for orchestrator review.","context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"4350c5dcbafca943afb1dc7bb4e70c782487d63a698dfddef01a6dc5f9ef43e5"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:15.052Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:15.052Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"c89ac39e59198ad22528e27877941b390c615d839c533c1a7ea8aa4ca0bbf6b6","after_hash":"4269311127ee8bab6ea51eb981f2eb7610b419e7e2bb389e322bd47fe8b1daa7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"ba153bfbb28b5152913425327d38206f5a0c4052fb79e990e912b6ecd10e8707"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:16.233Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/34","value":{"created_at":"2026-10-18T03:01:16.233Z","author":"codex-agent","text":"Audit: STALE / NOT MET literally at current main: acceptance names PM CLI/SDK 2026.10.4, while package and lock now pin 2026.10.13. Earlier certification and merged self-syncing dependency work record their own exact-head evidence, but they cannot certify the current dependency identity as 2026.10.4. Missing: orchestrator disposition of the obsolete version-specific item, rather than another stale certification run. No dependency changes or certification work performed; leave open."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:16.233Z"}],"before_hash":"4269311127ee8bab6ea51eb981f2eb7610b419e7e2bb389e322bd47fe8b1daa7","after_hash":"ca17862576b97f59078d1fd0bf5637f16b9f13e47210888cfcad6d0ae5fcc76d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d1aeb5e1cbe4913a69de4af366ba2f575ffe32a7a75de74ef9a9be5d1072c6ae"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:17.393Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:17.393Z"}],"before_hash":"ca17862576b97f59078d1fd0bf5637f16b9f13e47210888cfcad6d0ae5fcc76d","after_hash":"2f8ae9ac9bec8a28f5ea36766255efaa73ea1f0bff54e64e8d3737870f86a7c5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"89d71390bf8f8bb328be8bdf1d1c7936741c4303fcd502102ad48bb23f9672bc"} diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl new file mode 100644 index 00000000..346446e7 --- /dev/null +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -0,0 +1,23 @@ +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:18.320Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-rl-meta"},{"op":"add","path":"/metadata/title","value":"Improve bounded training recipes over public tracker histories"},{"op":"add","path":"/metadata/description","value":"Content-addressed bounded recipes, deterministic outer search, isolated repository splits and durable shared-budget inner loops with honest final-test reporting."},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-10-18T03:01:18.320Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-18T03:01:18.320Z"},{"op":"add","path":"/metadata/author","value":"codex-agent"},{"op":"add","path":"/metadata/acceptance_criteria","value":"Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates."},{"op":"add","path":"/metadata/parent","value":"pm-rl-apvf"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"0f81943d6e9c2391efd6bf4009d358b217aad453843998134c9b646f38b81bf8","item_hash_version":3,"message":"","context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"3e5277a891b49c3cc71fee9c21b628426429b137095e8a55e78942fce192bd0a"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:19.454Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:19.454Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"0f81943d6e9c2391efd6bf4009d358b217aad453843998134c9b646f38b81bf8","after_hash":"2fb6e037ef387a599ec1cac515133d4eb82981ba3eb252d0b90d519f7e2a27a5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a5e2bb0405a8d859846c1fb0ced116f3ece0a4f227349b51482d3c0830c1d158"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:21.043Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:21.043Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"2fb6e037ef387a599ec1cac515133d4eb82981ba3eb252d0b90d519f7e2a27a5","after_hash":"9ab1aa844c81f0f59d0230dcce7011a5b9fba7a4ecebd76a5e9bb563be70fcf8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"6e36f0beb9e15fc0e8e7be785bf462a80377707ff653ea3177e16f20756e2962"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:07:08.225Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:07:08.225Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-10-18T03:07:08.225Z","author":"codex-agent","text":"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change."}]}],"before_hash":"9ab1aa844c81f0f59d0230dcce7011a5b9fba7a4ecebd76a5e9bb563be70fcf8","after_hash":"421b39031debcf05a2fbfeb6edd3f58f13141cd9abde913104a5b22c93258c51","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d2b3189e73408c8c21bc8c15bba45b458474363cf7638e598b3d29d1eceabc75"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:07:12.042Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:07:12.042Z"},{"op":"add","path":"/metadata/files","value":[{"path":"dataset.ts","scope":"project"},{"path":"index.ts","scope":"project"},{"path":"loop.ts","scope":"project"},{"path":"meta.ts","scope":"project"},{"path":"package.json","scope":"project"},{"path":"recipe.ts","scope":"project"},{"path":"scripts/live-meta.ts","scope":"project"},{"path":"scripts/live-watchdog.ts","scope":"project"}]}],"before_hash":"421b39031debcf05a2fbfeb6edd3f58f13141cd9abde913104a5b22c93258c51","after_hash":"2dd08bc87423dd07480d42d0b33f3d9db3dedf71170d098fc73f9aaf06079a1d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"09888a55653db4d83b8e45c137bf29c78efd96d37f056957a0350f096cdc51eb"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:07:14.316Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:07:14.316Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/meta-recursive.md","scope":"project"},{"path":"README.md","scope":"project"},{"path":"RECURSIVE_TRAINING.md","scope":"project"}]}],"before_hash":"2dd08bc87423dd07480d42d0b33f3d9db3dedf71170d098fc73f9aaf06079a1d","after_hash":"5ed114ed4344fb1123e6bcd470e6b13644dbc81550ec74400be2e12e6d3fc846","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fe8582982ef4616130de33492d0806cc9591faa9f09a88a118cc5ab5819166ba"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:23:25.045Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/7/path","value":"scripts/live-meta.ts"},{"op":"replace","path":"/metadata/files/6/path","value":"recipe.ts"},{"op":"replace","path":"/metadata/files/5/path","value":"package.json"},{"op":"replace","path":"/metadata/files/4/path","value":"meta.ts"},{"op":"replace","path":"/metadata/files/3/path","value":"loop.ts"},{"op":"replace","path":"/metadata/files/2/path","value":"index.ts"},{"op":"replace","path":"/metadata/files/1/path","value":"examples/meta-trackers.json"},{"op":"add","path":"/metadata/files/8","value":{"path":"scripts/live-watchdog.ts","scope":"project"}},{"op":"add","path":"/metadata/files/9","value":{"path":"test/dataset.test.ts","scope":"project"}},{"op":"add","path":"/metadata/files/10","value":{"path":"test/fixtures/meta-workspace.ts","scope":"project"}},{"op":"add","path":"/metadata/files/11","value":{"path":"test/fixtures/tracker-histories.json","scope":"project"}},{"op":"add","path":"/metadata/files/12","value":{"path":"test/meta.test.ts","scope":"project"}},{"op":"add","path":"/metadata/files/13","value":{"path":"test/recipe.test.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:23:25.045Z"}],"before_hash":"5ed114ed4344fb1123e6bcd470e6b13644dbc81550ec74400be2e12e6d3fc846","after_hash":"3a40a993793cedd83e5c1103f046d25f508d72ebd6b898ef67a08442da224720","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"4a309da638280926d21143eb9c859a62d8b08efe419f89d1a5d1b57a8ec80dce"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:23:51.668Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:23:51.668Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node --test test/recipe.test.ts test/dataset.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T03:23:50.382Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}},{"command":"node --test test/meta.test.ts","scope":"project","timeout_seconds":1800,"provenance":{"author":"codex-agent","created_at":"2026-10-18T03:23:50.382Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}]}],"before_hash":"3a40a993793cedd83e5c1103f046d25f508d72ebd6b898ef67a08442da224720","after_hash":"3f29a5f2b690e7e44d8d28616b26de399734ddc37c0caa300a3bbaf8028adb49","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fc2a945245041e67dce1cbcb1c566f898d4b36dc0514bcf93d06ad7e4c571f4d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:24:16.558Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-10-18T03:24:16.558Z","author":"codex-agent","text":"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:24:16.558Z"}],"before_hash":"3f29a5f2b690e7e44d8d28616b26de399734ddc37c0caa300a3bbaf8028adb49","after_hash":"5225c04e1fdc1a3138cc16bb1a09cabc7f274c9b106e9433b3453713504f8ff2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"90a6ff4031990982c00d5f2c9d72bec1591344dc4886062d68145c87978b0356"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:31:31.203Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-10-18T03:31:31.203Z","author":"codex-agent","text":"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:31:31.203Z"}],"before_hash":"5225c04e1fdc1a3138cc16bb1a09cabc7f274c9b106e9433b3453713504f8ff2","after_hash":"7b3a1ec917e4ac6c5b59d31c582113f957bc6ee90e087b08faea280d11f84c00","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a63d627b7d61649cb929f6b12f8d162be98b968b0af706d1a1a5449672b92e31"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:43:08.885Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/2/path","value":"README.md"},{"op":"replace","path":"/metadata/docs/1/path","value":"docs/meta-recursive.md"},{"op":"replace","path":"/metadata/docs/0/path","value":"docs/meta-live-evidence.json"},{"op":"add","path":"/metadata/docs/3","value":{"path":"RECURSIVE_TRAINING.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:43:08.885Z"}],"before_hash":"7b3a1ec917e4ac6c5b59d31c582113f957bc6ee90e087b08faea280d11f84c00","after_hash":"73be1de9e2e47b71342b8896e07d79ca1106b65eac7f540354265c2ed2025086","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"714186ba1dc4d7e945747d450662157b82237b533b156671636ca25c9cb29f9d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:43:18.603Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-10-18T03:43:18.600Z","author":"codex-agent","text":"Live acceptance PASS: npm run test:live completed two meta-generations, K=2, over 25 public MIT repositories (15 train, 5 meta-validation, 5 final-test); one verified empty source omitted. Dataset a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c contains 1023 train, 145 inner held-out, 214 meta-validation, 385 final-test examples (1767 total). Initial recipe b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae: learning_rate=0.25, steps=2, batch=128, temperature=1, reward weights=1/0, selection=all, curriculum=forward. Generation 1 candidates 800886e9f4cd and 45113586500f; generation 2 candidates 4a48567235f1 and 55539a90ca05. Every resulting policy scored 107/214=0.5 on meta-validation: gain 0, lower confidence gain bound -0.21778781183411927, refusal no_statistical_improvement. Confidence 0.95 allocated across four comparisons gives 0.9875 each; effect threshold 0.01 and minimum samples 10 unchanged. No recipe promoted: inner promotion retained seed policies. Final untouched test before/after 198/385=0.5142857142857142. Dataset build plus controller 574489.248227 ms; parent watchdog unchanged at 15 minutes. Complete public source commits, recipes and verdicts: docs/meta-live-evidence.json. No improvement claim."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:43:18.603Z"}],"before_hash":"73be1de9e2e47b71342b8896e07d79ca1106b65eac7f540354265c2ed2025086","after_hash":"2927607e881f0a0b692d0a812adda5f5be537fbcc2a6ffbf5adc33d73400b494","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"b811ec2680a7d916ea909220a82a9f2749024fef29578518db0fddc50bc6d33a"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:47:00.856Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/13/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/12/path","value":"test/fixtures/tracker-histories.json"},{"op":"replace","path":"/metadata/files/11/path","value":"test/fixtures/meta-workspace.ts"},{"op":"replace","path":"/metadata/files/10/path","value":"test/fixtures/meta-controller.ts"},{"op":"add","path":"/metadata/files/14","value":{"path":"test/recipe.test.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:47:00.856Z"}],"before_hash":"2927607e881f0a0b692d0a812adda5f5be537fbcc2a6ffbf5adc33d73400b494","after_hash":"d32518045402d881302fff829485d88a74078ebecabee26a68ad45cfd0f8b708","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"663edcc8bfea73656f4a3b4a43cadcf92e1d1609971e29fca722c361ede8cb4b"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:47:10.210Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-10-18T03:47:10.210Z","author":"codex-agent","text":"Further real-controller regressions PASS 3/3: a physical outer-controller SIGKILL adopts the committed initial fit and original settled reservation; a high-signal synthetic fixture promotes a statistically better recipe and uses it as the next meta-generation incumbent; one shared Decision refuses expanded/replaced/oversubscribed budgets, including differently formatted reservation bodies. The full tracker read path remains certified. Normal local health exposes a global pm-github host-version skew (pinned 2026.10.13 versus global 2026.10.17); the isolated CI HOME/Git configuration passes strict health with only pre-existing advisory provenance debt (pm-rl-9uz4). No pin bump, telemetry configuration change or history repair performed. Linked pm test selection 1 passes 8/8; result tracking is disabled by existing project policy, so this comment retains the receipt."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:47:10.210Z"}],"before_hash":"d32518045402d881302fff829485d88a74078ebecabee26a68ad45cfd0f8b708","after_hash":"fb28cc6f5d6b461ec377e0d3e8ac3d61755c58a77d0878fc565861a918334d37","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d6e209cd0191cb3c741782c848a5ef69ce9037866434979212b71f011bee2e5b"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:50:38.780Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"tests_remove","patch":[{"op":"remove","path":"/metadata/tests/1"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:50:38.780Z"}],"before_hash":"fb28cc6f5d6b461ec377e0d3e8ac3d61755c58a77d0878fc565861a918334d37","after_hash":"00803b6558a76b79165e7b3f3de3928c189def6f978117e057e4e493b7793ff8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"c4fd9ecbc1482b1d020a59c86a1729231ef8737af44bf5a4434fe9c5adbe1757"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:50:43.234Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts","scope":"project","timeout_seconds":900,"provenance":{"author":"codex-agent","created_at":"2026-10-18T03:50:43.085Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:50:43.234Z"}],"before_hash":"00803b6558a76b79165e7b3f3de3928c189def6f978117e057e4e493b7793ff8","after_hash":"3227732588eff5a2ff4495cd4a8fcf98492350e87c07a8fc8f79bc76ec73a884","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"2674f34204a365920b7d0eed2eb59b047a296cfeff00581570f68b34ad26a963"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:55:02.575Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/15","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:55:02.575Z"}],"before_hash":"3227732588eff5a2ff4495cd4a8fcf98492350e87c07a8fc8f79bc76ec73a884","after_hash":"b9000bc89b699f07b06c20345dc308a2e1038de7d43ff767ee7b0adf09c4504d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"28649158c97b8d816c607083693c6a01c28a82aa9797ced73149b45b265e3a2e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:55:07.043Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-10-18T03:55:07.043Z","author":"codex-agent","text":"The search now receives sealed evaluator capabilities (fit, selection scores, final-test scores and dataset digest) rather than dataset readers. Dataset coordinates and all example loading stay in tracker-environment.ts; the proposer receives a fresh recipe-only request object. Terminal replay still succeeds with inner and final files unavailable, and the final-test callback runs after all promotion receipts. Unknown recipe knobs are rejected against the declared domain keys. The CLI optional seed/proposer defaults and camel-cased tracker option are fixed; direct real-tracker CLI and synthetic live-entry regressions pass 2/2. The physical-kill/promotion/shared-budget trio also passes 3/3 through the linked PM harness; result recording remains disabled by policy."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:55:07.043Z"}],"before_hash":"b9000bc89b699f07b06c20345dc308a2e1038de7d43ff767ee7b0adf09c4504d","after_hash":"f25ec057dc3b251f654435bec1a113550cd662bc4ec6cf3da48a920dbfb5b141","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e09314553110ef6f4d399dbabf99cb0440c98b71eba195ff348b709077b8f5c9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:58:51.495Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-10-18T03:58:51.495Z","author":"codex-agent","text":"Final real-data acceptance after evaluator capability isolation passes again: the complete dataset manifest and policy/gate/final-test report are byte-equivalent as JSON to the first successful run (same 25 eligible public repos, 1767 examples, four refused recipes, gain 0 with lower bound -0.21778781183411927, final-test 198/385 before and after). No statistical or feature tuning followed final-test exposure. The governing programme now binds the canonical approval item identity as well as its spec digest; an identical replacement Decision cannot switch budgets during resume. Full npm and Bun release gates follow with unchanged thresholds and CI identity isolation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:58:51.495Z"}],"before_hash":"f25ec057dc3b251f654435bec1a113550cd662bc4ec6cf3da48a920dbfb5b141","after_hash":"bf0863e1eb4164bf0941866ff9e555500faa97a20f92c9ea54daa3dd6d070770","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"5335fc803ff3e8d79b603c01cd87baab09237b52584572f423165943ea662ac4"} +{"hash_algorithm":"sha256","ts":"2026-10-18T04:05:27.268Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-10-18T04:05:27.268Z","author":"codex-agent","text":"Self-review tightened the evaluator boundary before the final gates: outer accounting and proposal recovery now perform certified Decision metadata listings with bodies excluded, then open only the stable reservation namespace or exact proposal-attempt record. They no longer request every tracker body, which could include inner environment/seed datasets. Reservation discovery uses stable item identities, so a title edit cannot hide an allocation. Regression cases include unrelated prose, copied envelopes, independent approvals and replacement Decisions with identical specs. The first release-gate attempt was deliberately interrupted for this correction; no passing full-gate result is claimed from it."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T04:05:27.268Z"}],"before_hash":"bf0863e1eb4164bf0941866ff9e555500faa97a20f92c9ea54daa3dd6d070770","after_hash":"da11ba831e2626ba2eb65d462f2b3ff40f209acc0eeb85f2ba2cf85cf5822e60","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"4635f2b951308d4b63558c81f9a202d9020047c717916a0d98b4c124e6932a4f"} +{"hash_algorithm":"sha256","ts":"2026-10-18T04:40:58.354Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/15/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/14/path","value":"test/fixtures/tracker-histories.json"},{"op":"replace","path":"/metadata/files/13/path","value":"test/fixtures/meta-workspace.ts"},{"op":"replace","path":"/metadata/files/12/path","value":"test/fixtures/meta-controller.ts"},{"op":"replace","path":"/metadata/files/11/path","value":"test/dataset.test.ts"},{"op":"replace","path":"/metadata/files/10/path","value":"scripts/live-watchdog.ts"},{"op":"replace","path":"/metadata/files/9/path","value":"scripts/live-meta.ts"},{"op":"replace","path":"/metadata/files/8/path","value":"recipe.ts"},{"op":"replace","path":"/metadata/files/7/path","value":"package.json"},{"op":"replace","path":"/metadata/files/6/path","value":"meta.ts"},{"op":"replace","path":"/metadata/files/5/path","value":"manifest.json"},{"op":"replace","path":"/metadata/files/4/path","value":"loop.ts"},{"op":"replace","path":"/metadata/files/3/path","value":"index.ts"},{"op":"replace","path":"/metadata/files/2/path","value":"examples/meta-trackers.json"},{"op":"replace","path":"/metadata/files/1/path","value":"examples/meta-approval.md"},{"op":"add","path":"/metadata/files/16","value":{"path":"test/recipe.test.ts","scope":"project"}},{"op":"add","path":"/metadata/files/17","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T04:40:58.354Z"}],"before_hash":"da11ba831e2626ba2eb65d462f2b3ff40f209acc0eeb85f2ba2cf85cf5822e60","after_hash":"bccf935e16a8f7cfbd07040c4e4607fbd002a00f7f8d29473838f7d26391cac9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"f78c0144f99ebbc55be09b028643aefe99580f97169356ffa803103ec9fb350a"} +{"hash_algorithm":"sha256","ts":"2026-10-18T04:41:07.624Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/3/path","value":"examples/meta-approval.md"},{"op":"replace","path":"/metadata/docs/2/path","value":"docs/meta-recursive.md"},{"op":"replace","path":"/metadata/docs/1/path","value":"docs/meta-live-evidence.json"},{"op":"replace","path":"/metadata/docs/0/path","value":"docs/durable-systemone-validation.md"},{"op":"add","path":"/metadata/docs/4","value":{"path":"README.md","scope":"project"}},{"op":"add","path":"/metadata/docs/5","value":{"path":"RECURSIVE_TRAINING.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T04:41:07.624Z"}],"before_hash":"bccf935e16a8f7cfbd07040c4e4607fbd002a00f7f8d29473838f7d26391cac9","after_hash":"d24b0d8148aea90d83ba305c15b2f95077fbdc961840e28532927a80659d4be4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fbc56f47c84ce26598848228d4e3cee0f540757af34cae4dfea0528e37f8882a"} +{"hash_algorithm":"sha256","ts":"2026-10-18T04:49:36.187Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-10-18T04:49:36.187Z","author":"codex-agent","text":"Final ledger regressions pass 3/3: interrupted atomic reservations retain one charge, independent programmes cannot oversubscribe, and approval replacement or copied/corrupt reservation tuples are refused. Programme identity, canonical approval ID, recipe plan and exact charge vector are bound into the durable receipt. Full npm and Bun release gates now run against the frozen implementation; thresholds and legacy deadlines remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T04:49:36.187Z"}],"before_hash":"d24b0d8148aea90d83ba305c15b2f95077fbdc961840e28532927a80659d4be4","after_hash":"4de067621814fec75fd8d58a54ae53427db6366198941342ee0249e9a604560a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2f9ffb620a5931ee9f7d3837ca3520c6dea774e1413efefcabb4970416c28424"} diff --git a/.agents/pm/history/pm-rl-mjo5.jsonl b/.agents/pm/history/pm-rl-mjo5.jsonl index 79744a41..5e563718 100644 --- a/.agents/pm/history/pm-rl-mjo5.jsonl +++ b/.agents/pm/history/pm-rl-mjo5.jsonl @@ -31,3 +31,6 @@ {"hash_algorithm":"sha256","ts":"2026-10-15T21:03:59.855Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7d3fa6b9c2cdba64d2aba754","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/12","value":{"created_at":"2026-10-15T21:03:59.855Z","author":"codex-agent","text":"Review round 1 final verdict: finding confirmed and fixed. Both npm run release:check and bun run release:check PASS 582/582 tests each, zero fail/skip/cancel/todo, unchanged exact 100/100/100/100 statement/line/branch/function coverage across 28 sources and 266 documented declarations. Zero duplication and production audit findings; identity, attestation, packaging and changelog checks pass under isolated CI Git/home settings. All 15 real Compose cases pass in both gates; 4/4 new cleanup regressions also pass via the linked PM snapshot test. Behavioural revert proofs (3/3 launch cases and 1/1 recovery case fail when only the relevant behavior is reverted) are recorded above. Gated source hashes match. Packed LM CLI measured 12623 ms npm and 12272 ms Bun within the unchanged 20000 ms bound. Cleanup failure remains visible as cleanup_failed and can require inspection of retained job resources; existing timing and kernel quota follow-ups remain unchanged. No new PM CLI/SDK defect encountered; test result tracking is disabled by project policy. Leaving the item open for orchestrator verification and releasing the claim."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-15T21:03:59.855Z"}],"before_hash":"b519896010d5603276f1a19115e8dfe0bd3e78825efb86dd65dc15b9c3a8237c","after_hash":"38902a0075e18c4ef8a1cc1157183b710fffba4e91f2947462e1ced609570404","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"bc7372332c9ef36072e7f21119ca2a5eb31efa3971209b28662a10cc91b8019b"} {"hash_algorithm":"sha256","ts":"2026-10-15T21:04:01.562Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7d3fa6b9c2cdba64d2aba754","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-15T21:04:01.562Z"}],"before_hash":"38902a0075e18c4ef8a1cc1157183b710fffba4e91f2947462e1ced609570404","after_hash":"21d8d66684281a416c5c84fe244d704d01d3a9d0a762fb9c267e6aaa937c52e9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"2d1c36c50b604f84b344de63a2736bbec58b629a7f655501f266e5c1c7a56038"} {"hash_algorithm":"sha256","ts":"2026-10-15T21:36:08.213Z","author":"claude-orchestrator","author_source":"asserted","agent_harness":"claude-code","agent_model":"claude-opus-5-5","agent_model_source":"probe","agent_instance":"cd687996088c07eef02d762c","agent_provenance":{"model":{"value":"claude-opus-5-5","source":"probe"},"effort":{"value":"xhigh","source":"environment"},"role":null,"topic":null,"version":{"value":"2.1.301","source":"probe"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/13","value":{"created_at":"2026-10-15T21:36:08.213Z","author":"claude-orchestrator","text":"Review round 2 (CodeRabbit thread on docs/process-trainer.md:211): the Compose cleanup paragraph said a failed cleanup refuses progression, contradicting the cleanup-diagnostic section and executeReservedProcessJob (cleanup_failed is recorded separately and preserves a validated completion, cancellation or trainer error). Sentence replaced so both sections agree; doc-only change."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-15T21:36:08.213Z"}],"before_hash":"21d8d66684281a416c5c84fe244d704d01d3a9d0a762fb9c267e6aaa937c52e9","after_hash":"455def3024a63f7632426fa1858e214ce4b9a23c4ae14b2a30be18f072869dec","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"claude_session_file","rule_version":"v1"},"version":{"status":"resolved","resolver":"claude_session_file","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"22694672ace89397d43a84673d7f19026745da2ae26dda452ae868f2ad0784c8"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:07.796Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:07.796Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"455def3024a63f7632426fa1858e214ce4b9a23c4ae14b2a30be18f072869dec","after_hash":"6a474178892067c0fde23136f830b51e6dbe86ef536f90837098ef245106c179","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"805d0d6ab2152f24542fab691d378fdd0efcb780588bac70df7969efc9364a24"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:08.923Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/14","value":{"created_at":"2026-10-18T03:01:08.923Z","author":"codex-agent","text":"Audit: MET against recorded acceptance. Merged PR #79 (2018b585bce8aa55f0d1c6483001f65a3a7190da) adds Compose execution through the existing durable job, atomic reservation and receipt contract. Fifteen real-container tests retain ownership, staging, cancellation, contention, crash/recovery and successor evidence, including four cleanup-error regressions with behavioural revert failures. Both isolated release gates passed 582/582 at exact 100% in all four dimensions; merged PR #80 subsequently passed 590/590. Kernel CPU/storage follow-up pm-rl-7073 is a separate scope. No missing criterion found; leave open for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:08.923Z"}],"before_hash":"6a474178892067c0fde23136f830b51e6dbe86ef536f90837098ef245106c179","after_hash":"08c54abf8f93cb2857c1360d72a3caf4b35095de116e1e6a6bd00df0f1428ae7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7aae15043c1f6e8ec355082f786734f0acd17bd35539a724c242652bff8d02f4"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:10.041Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:10.041Z"}],"before_hash":"08c54abf8f93cb2857c1360d72a3caf4b35095de116e1e6a6bd00df0f1428ae7","after_hash":"de0fb95ce2910cb025843cedd67d8838e5087601b843510fbb1627f8dccce2bc","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"2b550a2bdc528cde69676c063232ab245435a81504646982ab99a3ff0639497b"} diff --git a/.agents/pm/history/pm-rl-whrd.jsonl b/.agents/pm/history/pm-rl-whrd.jsonl index 8ee6baf5..c74622f9 100644 --- a/.agents/pm/history/pm-rl-whrd.jsonl +++ b/.agents/pm/history/pm-rl-whrd.jsonl @@ -39,3 +39,6 @@ {"hash_algorithm":"sha256","ts":"2026-10-16T05:51:23.733Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6c53759a996b88aafc5a5f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/21","value":{"created_at":"2026-10-16T05:51:23.733Z","author":"codex-agent","text":"Extended CI parity: the failed GitHub job used Node 26.12.0, while initially installed Node 26 was 26.7.0. Installed the exact 26.12.0 runtime with verified download checksum. Three diagnostic original-source contention probes also passed on 26.12.0, so the historical refusal remains unconfirmed. The final synchronized test now independently passes 20/20 on each of Node 22.23.1, 26.7.0 and 26.12.0 (60/60, zero failures/skips). Re-fetched main; it remains an ancestor, so no merge is needed. Literal Bun release gate at source 91d40fc passes 590/590, zero failures/skips/cancellations, all four coverage dimensions 100% across 30 sources, 272 documented declarations, and all audit/package/changelog checks. First npm attempt retains 589/590 with only the packed CLI child reaching its unchanged 25000 ms timeout; concurrent diagnostic probes added load, so that attempt is not passing gate evidence. Serial npm retry is now running alone on exact CI Node 26.12.0."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-16T05:51:23.733Z"}],"before_hash":"fa732fb5df48b0210804228c782079ab94e8fbd6bc68cf9b2fca143d06c8b64e","after_hash":"0e7089c38bb07105a8ec9efbcde9f9ff485d04b5664c6741d4d8aa37de0bd69f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"22f79158dbf99f358539e70ff661c48ba00510935b327a94f16d9d4bd585cc51"} {"hash_algorithm":"sha256","ts":"2026-10-16T06:12:44.947Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6c53759a996b88aafc5a5f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/22","value":{"created_at":"2026-10-16T06:12:44.947Z","author":"codex-agent","text":"Final local delivery at source/test commit 91d40fc: literal npm run release:check on Node 26.12.0 exits 0 with 590/590 passing, zero failed/skipped/cancelled, all four coverage dimensions 100% over all 30 sources, 272 documented declarations, and identity/audit/package/changelog checks passed. Literal bun run release:check on Node 26.7.0 and Bun 1.3.5 also exits 0 with 590/590 and the same unchanged four 100% thresholds. Packed CLI measured 10996.891 ms (npm retry) and 11086.851 ms (Bun). Preserve the first npm attempt: 589/590, sole unchanged 25000 ms packed CLI timeout; it is not passing gate evidence. Final contention loops are 20/20 each on Node 22.23.1, 26.7.0 and exact CI 26.12.0. The original CI winner refusal cannot be recovered from its log and did not reproduce; the reservation barrier invariant is proved, but the historical timeout root cause remains unconfirmed. Cleanup independently verifies zero repository Compose containers, and three owned validation images were removed after checking their exact owner label. Original history byte prefixes remain unchanged for both touched items. Main is already an ancestor; ready to push and wait for GitHub checks, without merging or resolving threads."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-16T06:12:44.947Z"}],"before_hash":"0e7089c38bb07105a8ec9efbcde9f9ff485d04b5664c6741d4d8aa37de0bd69f","after_hash":"4acea874a351b48c7cb28f3c7ea84d12235391797229b0ec84674d10f099771e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"61d2c2568eabd57ce902efbb95fd1b205184d527c0af9f33dd3cecb9c80665a0"} {"hash_algorithm":"sha256","ts":"2026-10-16T06:12:51.664Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6c53759a996b88aafc5a5f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-16T06:12:51.664Z"}],"before_hash":"4acea874a351b48c7cb28f3c7ea84d12235391797229b0ec84674d10f099771e","after_hash":"30b0dd19789308a01bfab726a63188834f14bd2c6a5887b5c650f91cf2e08e33","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"8584656a2f2418f56c9d502dfe10ec4ea5163feb16a93aedb7bfbcc6e6b29860"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:03.019Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:03.019Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"30b0dd19789308a01bfab726a63188834f14bd2c6a5887b5c650f91cf2e08e33","after_hash":"9a13046fe34590389b172bbe47314784d192ed1563e486033eda92fae3e17829","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e81d619b73de97e750152eecf384156febd3570b9027bdf1f2e063031731dbb5"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:05.676Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/23","value":{"created_at":"2026-10-18T03:01:05.676Z","author":"codex-agent","text":"Audit: MET against recorded acceptance. Merged PR #80 (b255dfac6543ab178ab2720fad1de1ba49f91dd4) supplies two real external LM generations and successor collection, SIGKILL staged-completion recovery without retraining or double charge, cancellation, corrupt checkpoint and resource refusals, and one-launch contention. docs/lm-adapter.md and test/lm-compose.test.ts retain measured evidence; feature and fixture behavioural revert proofs are recorded. Final isolated npm and Bun release gates each passed 590/590 with exact four-metric 100% coverage. No acceptance gap found in merged evidence; storage kernel enforcement remains separately tracked in pm-rl-7073. Leave open for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:05.676Z"}],"before_hash":"9a13046fe34590389b172bbe47314784d192ed1563e486033eda92fae3e17829","after_hash":"f0db1203551b4fffe4f7cf0e615fd1fedfb3746fb9d9cae885d714b1106948a9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a2825b08164844101c109aae6748dd047b5887a4fc602e8d7d4dcaf46bcb93d3"} +{"hash_algorithm":"sha256","ts":"2026-10-18T03:01:06.851Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:06.851Z"}],"before_hash":"f0db1203551b4fffe4f7cf0e615fd1fedfb3746fb9d9cae885d714b1106948a9","after_hash":"b706e3d807672f71be9886b8b269387f16fc52f145a3175316e212cd5a3e685e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"6928c08c6712a4a68e78f2598b68e21a48557b8c77f837af7041da8771de0420"} diff --git a/.agents/pm/tasks/pm-rl-bi4v.toon b/.agents/pm/tasks/pm-rl-bi4v.toon index e1da281c..d6e7a9e8 100644 --- a/.agents/pm/tasks/pm-rl-bi4v.toon +++ b/.agents/pm/tasks/pm-rl-bi4v.toon @@ -6,11 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-15T22:41:40.256Z" -updated_at: "2026-10-16T03:47:23.897Z" +updated_at: "2026-10-18T03:01:14.190Z" author: codex-agent acceptance_criteria: A baseline/candidate timing reproduction identifies the cause; the real eight-boundary drill and complete release gates pass with the existing 300-second timeout and unchanged coverage thresholds. parent: pm-rl-apvf -comments[8]{created_at,author,text}: +comments[9]{created_at,author,text}: "2026-10-15T22:50:30.933Z",codex-agent,"Diagnostic baseline: an isolated origin/main source archive, using the same pinned dependencies, passed node --test --test-concurrency=1 --experimental-test-coverage --test-coverage-include=*.ts --test-coverage-include=scripts/*.ts --test-name-pattern=\"SIGKILL at every HTTP-to-PM\" test/decision-recovery.test.ts in 276105.853 ms (1/1). The candidate full release run reached the unchanged 300000 ms timeout. This establishes a narrow baseline timing margin; it does not by itself attribute the full-run failure. Keep all eight boundaries and the original timeout. A complete passing candidate gate is still required." "2026-10-15T22:55:58.563Z",codex-agent,"The eight crash scenarios use independent trackers and synthetic servers. Run the training/held-out pair concurrently for each of the four boundaries, with at most two scenarios active. Keep every real SIGKILL, replay, physical-request, token, identity and idempotency assertion and the original 300000 ms timeout. This changes scheduling only and avoids eight serial setup/replay intervals consuming the whole wall allowance. Verify the focused case under coverage, then require complete npm and Bun release gates." "2026-10-15T23:01:06.478Z",codex-agent,"The bounded pair schedule passed all eight real boundary scenarios under coverage in 254328.583 ms (1/1 test, zero skips). The isolated serial main-source diagnostic measured 276105.853 ms; the earlier serial full candidate hit 300000 ms. These are shared-host observations, not a controlled speedup claim. The diff changes only outer loop order and Promise.all of two independent metric cases; every assertion and the 300000 ms timeout remain." @@ -19,6 +19,7 @@ comments[8]{created_at,author,text}: "2026-10-16T00:09:31.940Z",codex-agent,"Focused verification with an explicit raw V8 parent directory passed all eight boundaries in 137862.796 ms (1/1, zero skips). Behavioural guard-removal proof in an isolated source snapshot: remove only empty execArgv and NODE_V8_COVERAGE suppression from launch, retain the new child observation and all assertions, then run the covered case; it fails 0/1 in 8975.060 ms with SIGKILL controller inherited V8 coverage. Restoring isolation passes 1/1. This changes neither source coverage scope nor test deadlines; built child dist code is not one of the gated TypeScript sources, and parent source APIs remain exercised." "2026-10-16T00:15:13.400Z",codex-agent,"Latest PM-linked verification passes 1/1 with all eight boundaries, zero skips: case 206859.047 ms inside the unchanged 300000 ms test deadline. The full-gate child inheritance regression is explicitly checked at bootstrap; guard removal fails and restored isolation passes. The child also runs with the actual scratch project cwd. No authored source is excluded from coverage, and no test assertion or deadline was removed." "2026-10-16T03:47:19.355Z",codex-agent,"Final verification: both complete npm and Bun release gates pass 590/590, zero skips, all four coverage dimensions 100%. All eight real HTTP crash boundaries pass within the unchanged 300-second test limit. Independent datasets execute in bounded pairs; SIGKILL children report and enforce coverage isolation; the parent still covers the complete source inventory. Removing child coverage isolation fails the runtime regression, restored execution passes. No assertion, deadline or threshold was weakened. Leave open for orchestrator verification." + "2026-10-18T03:01:13.159Z",codex-agent,"Audit: MET against recorded acceptance in merged PR #80. The serial baseline measured 276105.853 ms; concurrent full runs hit the unchanged 300000 ms limit. Forked crash children inherited V8 coverage; isolated child execArgv and raw coverage output plus bounded independent pairs retain all eight real HTTP-to-PM crash boundaries. Guard-only revert fails with inherited-coverage evidence; restored focused and linked runs pass. Both full release gates passed 590/590 with all eight boundaries within 300000 ms and unchanged four-metric thresholds. No remaining acceptance gap in that evidence; leave open for orchestrator verification." files[2]{path,scope}: test/decision-recovery.test.ts,project test/fixtures/decision-controller.ts,project diff --git a/.agents/pm/tasks/pm-rl-mjo5.toon b/.agents/pm/tasks/pm-rl-mjo5.toon index 909e62ff..8a6c938b 100644 --- a/.agents/pm/tasks/pm-rl-mjo5.toon +++ b/.agents/pm/tasks/pm-rl-mjo5.toon @@ -6,11 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-14T19:46:39.492Z" -updated_at: "2026-10-15T21:36:08.213Z" +updated_at: "2026-10-18T03:01:10.041Z" author: codex-agent acceptance_criteria: "Compose execution preserves launch ownership and process contract, retains staging on failure, and passes real reservation and recovery drills" parent: pm-rl-apvf -comments[14]{created_at,author,text}: +comments[15]{created_at,author,text}: "2026-10-15T10:58:38.098Z",codex-agent,"Design: reuse the process job fence, reservation transaction, receipt validator and settlement state machine. Add a trusted Compose launcher with a job-derived project identity and generated isolated staging configuration; mount only job staging and retain all protocol artifacts. Exercise real success, container death, cancellation, contention and two-generation successor collection. Behavioural revert proofs will remove only the relevant launcher or selection behaviour in an isolated snapshot." "2026-10-15T11:08:14.363Z",codex-agent,"Real Docker findings: a capability-restricted container must use the invoking numeric UID/GID to write host staging. Compose down/rm omit one-off run containers on the tested version, so cleanup resolves only the exact job-named container with matching project/service labels and removes its immutable daemon ID before project-scoped down. Project names also hash staging scope to isolate identical jobs in independent trackers. Receipt validation, conservative settled charges and controller fences remain shared with local execution." "2026-10-15T11:11:10.946Z",codex-agent,"Drill progress: launch/receipt/replay, container death, cancellation, two real controller contention, staged-completion SIGKILL recovery and orphan cleanup pass. The two-generation Compose run promoted both changed policies, and generation two collection identifies generation one policy. Kernel CPU/storage quotas are a distinct follow-up to the existing reported-use and polling contract. Full release gates run directly under isolated CI Git/home settings; pm test --run --progress passed the linked typecheck, but project policy reports tracking_disabled so durable gate results are recorded in comments." @@ -25,6 +25,7 @@ comments[14]{created_at,author,text}: "2026-10-15T20:37:13.115Z",codex-agent,"Review round 1 npm release gate PASS: npm run release:check under isolated CI Git/home settings passed 582/582 tests, zero fail/skip/cancel/todo. Coverage remains exact 100/100/100/100 statement/line/branch/function across 28 authored sources; 266 documented declarations, zero duplication and production audit findings; identity, attestation, packaging and changelog checks passed. All 15 real Compose tests passed. Existing LM CLI timing measured 12623 ms within the unchanged 20000 ms bound. Running the unchanged full Bun gate next." "2026-10-15T21:03:59.855Z",codex-agent,"Review round 1 final verdict: finding confirmed and fixed. Both npm run release:check and bun run release:check PASS 582/582 tests each, zero fail/skip/cancel/todo, unchanged exact 100/100/100/100 statement/line/branch/function coverage across 28 sources and 266 documented declarations. Zero duplication and production audit findings; identity, attestation, packaging and changelog checks pass under isolated CI Git/home settings. All 15 real Compose cases pass in both gates; 4/4 new cleanup regressions also pass via the linked PM snapshot test. Behavioural revert proofs (3/3 launch cases and 1/1 recovery case fail when only the relevant behavior is reverted) are recorded above. Gated source hashes match. Packed LM CLI measured 12623 ms npm and 12272 ms Bun within the unchanged 20000 ms bound. Cleanup failure remains visible as cleanup_failed and can require inspection of retained job resources; existing timing and kernel quota follow-ups remain unchanged. No new PM CLI/SDK defect encountered; test result tracking is disabled by project policy. Leaving the item open for orchestrator verification and releasing the claim." "2026-10-15T21:36:08.213Z",claude-orchestrator,"Review round 2 (CodeRabbit thread on docs/process-trainer.md:211): the Compose cleanup paragraph said a failed cleanup refuses progression, contradicting the cleanup-diagnostic section and executeReservedProcessJob (cleanup_failed is recorded separately and preserves a validated completion, cancellation or trainer error). Sentence replaced so both sections agree; doc-only change." + "2026-10-18T03:01:08.923Z",codex-agent,"Audit: MET against recorded acceptance. Merged PR #79 (2018b585bce8aa55f0d1c6483001f65a3a7190da) adds Compose execution through the existing durable job, atomic reservation and receipt contract. Fifteen real-container tests retain ownership, staging, cancellation, contention, crash/recovery and successor evidence, including four cleanup-error regressions with behavioural revert failures. Both isolated release gates passed 582/582 at exact 100% in all four dimensions; merged PR #80 subsequently passed 590/590. Kernel CPU/storage follow-up pm-rl-7073 is a separate scope. No missing criterion found; leave open for orchestrator verification." files[7]{path,scope}: compose.ts,project index.ts,project diff --git a/README.md b/README.md index b83ac8a9..d7ac59b2 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ For decision-model training, select `"trainer": "systemone"` and provide a disjoint labelled PM items in `training`/`evaluation`, and the bounds described in [the adapter contract](docs/durable-systemone-validation.md). No new runtime dependency is required. The packaged `examples/loop-systemone.json` supplies a complete two-generation -configuration for the same synthetic demonstration. Run `npm run test:live` +configuration for the same synthetic demonstration. Run `npm run test:live:systemone` locally for two real `tev1:4b` generations. Override `SYSTEMONE_BASE_URL` and `SYSTEMONE_MODEL` for another TypeSafe-compatible service. CI uses real in-process HTTP servers and never calls Ollama. @@ -231,6 +231,25 @@ All exit non-zero. The gap-widening check needs at least two consecutive gaps, s ## Recursive self-improvement, and the four properties that make it honest +`pm rl meta run` also searches the bounded recipe that trains each candidate. +The programme names a versioned content-addressed initial recipe; every inner +generation records its recipe digest. Seeded search can vary learning rate, +steps, batch, data selection, curriculum, temperature and reward-shaping weights +within declared domains. Optional local `tev1:4b` proposals use the existing +calibration adapter and fall back to seeded search when unavailable. One existing +Decision bounds the entire search and every inner process fit through atomic +reservations; the loop cannot enlarge that approval. + +Recipe selection receives only exact-match meta-validation evidence from separate +public tracker repositories. Inner held-out data stays in its evaluator; the +proposer has no dataset capability. A proxy-only gain is refused by the existing +statistical gate. The final-test repositories are opened only after all recipe +promotions, and report the initial versus selected policy without influencing +selection. [The meta-recursive contract](docs/meta-recursive.md) documents the +data boundary, confidence assumptions, idempotent resume and measured real-data +acceptance. Start with [the bounded programme](examples/meta-trackers.json) and +`pm rl dataset build --from-trackers --output `. + The current pm-rl runtime **executes, tracks and gates** a bounded numerical loop: a generation collects trajectories, the built-in bandit trainer produces a successor, and the successor collects the next generation's trajectories. `pm rl loop run` executes these steps with the built-in contextual diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 3ef35f26..501fef5a 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -63,6 +63,16 @@ Adapters report structured progress and completion evidence over a documented st 4. **Met for local process and Compose adapters:** real SIGKILL after staged completion and before its receipt commit recovers without retraining or double charge; planning/evaluation/promotion crashes and mid-fit SIGTERM retain evidence. Crash and cancellation drills cover every transition, including a complete checkpoint without a committed receipt. Restart is idempotent and does not overwrite prior artifacts. 5. **Met for local process and Compose adapters:** dataset overlap, reward/environment drift, excessive gap, missing/corrupt receipts, invalid checkpoints and exceeded resource allowances refuse progression; failed candidates never collect the next generation. Contamination, a training-to-evaluation gap above `maximum_gap`, stale reward or environment identity, corrupt checkpoints, missing metrics and exceeded resource limits prevent promotion. A failed candidate cannot become the next collection policy. 6. Unit, real-process integration, CLI acceptance, replay, performance and failure-path tests cover every authored source file at exact statement/line/branch/function thresholds. The docstring gate covers the declared source surface, and the scope inventory names anything it excludes. +7. **Meta-recursive recipe improvement:** `pm rl meta run` names and evolves a + content-addressed bounded recipe, executes bounded inner loops under one + pre-approved Decision with atomic reservations, and promotes recipes only + through the existing statistical gate on repository-isolated meta-validation + evidence. Inner held-out examples are confined to their evaluator; final-test + repositories are opened only after selection. Real public MIT tracker histories + carry source repository and commit identity. The builder excludes hosted data, + pm-web and pm-gpt. [The contract and live evidence](docs/meta-recursive.md) and + [pm-rl-meta](.agents/pm/features/pm-rl-meta.toon) track this criterion; its + real-data and full-gate acceptance is pending until measured below. ## Data boundary and capacity diff --git a/dataset.ts b/dataset.ts new file mode 100644 index 00000000..934d3117 --- /dev/null +++ b/dataset.ts @@ -0,0 +1,165 @@ +/** Public, commit-pinned tracker histories projected to a small redistributable lifecycle task. */ +import assert from "node:assert/strict"; +import { execFileSync } from "node:child_process"; +import { mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { hashJson, type JsonValue } from "./index.ts"; + +/** Repository isolation roles; inner held-out items come only from the training repositories. */ +export const TRACKER_SPLITS = ["train", "inner-held-out", "meta-validation", "final-test"] as const; +/** One sealed dataset compartment. */ +export type TrackerSplit = typeof TRACKER_SPLITS[number]; +/** A prefix contains only normalized lifecycle states, never titles, comments, identities or free text. */ +export interface TrackerExample { + readonly id: string; + readonly repo: string; + readonly commit: string; + readonly prefix: readonly string[]; + readonly label: "completed" | "cancelled"; +} +/** Snapshot manifest binds split content, repository roles and source license declarations. */ +export interface TrackerDataset { + readonly format: "pm-rl/tracker-dataset/1"; + readonly task: "terminal-disposition"; + readonly seed: number; + readonly omitted_sources: readonly { readonly repo: string; readonly commit: string; readonly reason: "no_prefixed_terminal_transition" }[]; + readonly sources: readonly { readonly repo: string; readonly commit: string; readonly license: "MIT"; readonly role: "train" | "meta-validation" | "final-test" }[]; + readonly splits: Readonly>; + readonly digest: string; +} + +/** Invoke bounded read-only Git/GitHub operations without shell evaluation of tracker content. */ +function sourceCommand(command: string, args: string[], cwd: string): string { + return execFileSync(command, args, { cwd, encoding: "utf8", timeout: 30_000, maxBuffer: 8 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] }).trim(); +} + +/** Read selected committed blobs in one bounded Git process, preserving byte lengths for Unicode history. */ +function historyBlobs(root: string, commit: string, paths: readonly string[]): string[] { + const bytes = execFileSync("git", ["cat-file", "--batch"], { cwd: root, input: paths.map((path) => `${commit}:${path}\n`).join(""), + timeout: 30_000, maxBuffer: 64 * 1024 * 1024, stdio: ["pipe", "pipe", "pipe"] }); + let offset = 0; + return paths.map(() => { + const end = bytes.indexOf(10, offset); + const header = bytes.subarray(offset, end).toString("ascii"); + assert.match(header, /^[a-f0-9]{40} blob \d+$/, "dataset_history_blob"); + const length = Number(header.slice(header.lastIndexOf(" ") + 1)); + assert.ok(length <= 8 * 1024 * 1024, "dataset_history_bytes"); + offset = end + 1 + length + 1; + return bytes.subarray(end + 1, offset - 1).toString("utf8"); + }); +} + +/** Extract the first terminal outcome from append-only history, excluding that outcome from its prefix. */ +export function trackerHistoryExample(history: string, repo: string, commit: string, item: string): TrackerExample | null { + const prefix: string[] = []; + for (const line of history.split("\n").filter(Boolean)) { + const event = JSON.parse(line) as { patch?: readonly { path: string; value?: unknown; op?: string }[] }; + for (const patch of event.patch ?? []) { + if (patch.path !== "/metadata/status" || patch.op === "remove") continue; + const status = String(patch.value); + if (["closed", "canceled", "cancelled"].includes(status)) { + if (prefix.length === 0) return null; // Imported terminal snapshots carry no predictive prefix. + return { id: hashJson({ repo, item }), repo, commit, prefix, + label: status === "closed" ? "completed" : "cancelled" }; + } + assert.ok(["open", "in_progress", "blocked"].includes(status), `dataset_unknown_status: ${status.slice(0, 32)}`); + prefix.push(status); + } + } + return null; +} + +/** Build only from committed public MIT tracker histories; explicitly deny hosted and excluded repositories. */ +export function buildTrackerDataset(directories: readonly string[], output: string, seed = 42): TrackerDataset { + assert.ok(directories.length >= 3 && directories.length <= 64 && Number.isInteger(seed) && seed >= 0 && seed <= 0xffff_ffff, "dataset_bounds"); + const inspected = directories.map((directory) => { + const path = realpathSync(directory); + assert.ok(!path.split("/").some((part) => ["pm-hosted-data", "pm-web", "pm-gpt"].includes(part)), "dataset_forbidden_source"); + const root = dirname(dirname(path)); + assert.equal(path, join(root, ".agents", "pm"), "dataset_tracker_directory"); + const remote = sourceCommand("git", ["remote", "get-url", "origin"], root); + const match = /^(?:https:\/\/github\.com\/|git@github\.com:)([\w-]+\/pm-[\w-]+?)(?:\.git)?$/.exec(remote); + assert.ok(match !== null, "dataset_github_source"); + const repo = match[1]; + assert.ok(!["pm-web", "pm-gpt", "pm-cli"].includes(repo.split("/")[1]), "dataset_excluded_repo"); + const metadata = JSON.parse(sourceCommand("gh", ["repo", "view", repo, "--json", "visibility,licenseInfo,nameWithOwner"], root)) as { visibility: string; licenseInfo: { key: string } | null; nameWithOwner: string }; + assert.ok(metadata.visibility === "PUBLIC" && metadata.licenseInfo?.key === "mit" && metadata.nameWithOwner.toLowerCase() === repo.toLowerCase(), "dataset_public_mit_required"); + const commit = sourceCommand("git", ["rev-parse", "HEAD"], root); + assert.match(commit, /^[a-f0-9]{40}$/, "dataset_commit"); + assert.equal(sourceCommand("gh", ["api", `repos/${repo}/commits/${commit}`, "--jq", ".sha"], root), commit, "dataset_public_commit_required"); + const paths = sourceCommand("git", ["ls-tree", "-r", "--name-only", commit, "--", ".agents/pm/history"], root).split("\n"); + assert.ok(paths.length <= 10_000, "dataset_history_limit"); + const examples: TrackerExample[] = []; + const selected = paths.filter((name) => /^\.agents\/pm\/history\/[\w.-]+\.jsonl$/.test(name)); + const histories = historyBlobs(root, commit, selected); + for (const [index, file] of selected.entries()) { + const example = trackerHistoryExample(histories[index], repo, commit, file); + if (example !== null) examples.push(example); + } + return { repo, commit, examples }; + }); + assert.equal(new Set(inspected.map((source) => source.repo.toLowerCase())).size, inspected.length, "dataset_duplicate_repo"); + const snapshots = inspected.filter((source) => source.examples.length > 0); + const omitted_sources = inspected.filter((source) => source.examples.length === 0).map((source) => ({ repo: source.repo, commit: source.commit, reason: "no_prefixed_terminal_transition" as const })); + assert.ok(snapshots.length >= 3, "dataset_eligible_sources"); + snapshots.sort((a, b) => hashJson({ repo: a.repo, seed }).localeCompare(hashJson({ repo: b.repo, seed }))); + const data: Record = { train: [], "inner-held-out": [], "meta-validation": [], "final-test": [] }; + const trainCount = Math.max(1, Math.floor(snapshots.length * 0.6)); + const validationEnd = Math.max(trainCount + 1, Math.floor(snapshots.length * 0.8)); + // Identical observable prefixes stay together, even across training repositories. This also preserves + // the process adapter's stricter refusal of duplicate feature/reward content across its inner split. + const groups = [...new Set(snapshots.slice(0, trainCount).flatMap((source) => source.examples.map((example) => hashJson([...example.prefix]))))].sort(); + const innerGroups = new Set(groups.filter((_group, index) => index % 5 === 0)); + const sources = snapshots.map((source, index) => { + const role: "train" | "meta-validation" | "final-test" = index < trainCount ? "train" : index < validationEnd ? "meta-validation" : "final-test"; + for (const example of source.examples) { + const split = role === "train" && innerGroups.has(hashJson([...example.prefix])) ? "inner-held-out" : role; + data[split].push(example); + } + return { repo: source.repo, commit: source.commit, license: "MIT" as const, role }; + }); + const splits = {} as Record; + for (const split of TRACKER_SPLITS) { + const examples = data[split].sort((a, b) => a.id.localeCompare(b.id)); + assert.ok(examples.length > 0 && examples.length <= 10_000, "dataset_split_size"); + splits[split] = { digest: hashJson(examples as unknown as JsonValue), count: examples.length }; + } + const record = { format: "pm-rl/tracker-dataset/1" as const, task: "terminal-disposition" as const, seed, sources, omitted_sources, splits }; + const manifest = { ...record, digest: hashJson(record as unknown as JsonValue) }; + mkdirSync(output, { recursive: true }); + for (const split of TRACKER_SPLITS) writeFileSync(join(output, `${split}.json`), JSON.stringify(data[split]), { flag: "wx" }); + writeFileSync(join(output, "dataset.json"), JSON.stringify(manifest, null, 2), { flag: "wx" }); + return manifest; +} + +/** Verify a dataset manifest without opening held-out or final-test compartments. */ +export function readTrackerDataset(directory: string): TrackerDataset { + const { digest, ...record } = JSON.parse(readFileSync(join(directory, "dataset.json"), "utf8")) as TrackerDataset; + assert.equal(hashJson(record as unknown as JsonValue), digest, "dataset_manifest_identity"); + assert.ok(record.format === "pm-rl/tracker-dataset/1" && record.task === "terminal-disposition", "dataset_format"); + assert.equal(new Set(record.sources.map((source) => source.repo)).size, record.sources.length, "dataset_duplicate_repo"); + return { ...record, digest }; +} + +/** Open exactly one compartment, verifying content identity, provenance, bounds and repository isolation. */ +export function readTrackerSplit(directory: string, manifest: TrackerDataset, split: TrackerSplit): readonly TrackerExample[] { + const examples = JSON.parse(readFileSync(resolve(directory, `${split}.json`), "utf8")) as TrackerExample[]; + const spec = manifest.splits[split]; + assert.equal(hashJson(examples as unknown as JsonValue), spec.digest, "dataset_split_identity"); + assert.ok(examples.length > 0 && examples.length <= 10_000 && examples.length === spec.count, "dataset_split_size"); + assert.equal(new Set(examples.map((example) => example.id)).size, examples.length, "dataset_duplicate_example"); + for (const example of examples) { + const source = manifest.sources.find((entry) => entry.repo === example.repo); + const role = split === "inner-held-out" ? "train" : split; + assert.ok(source !== undefined && source.role === role && source.commit === example.commit && source.license === "MIT", "dataset_repo_leakage"); + assert.ok(example.label === "completed" || example.label === "cancelled", "dataset_label"); + assert.ok(example.prefix.length > 0 && example.prefix.every((status) => ["open", "in_progress", "blocked"].includes(status)), "dataset_prefix"); + } + return examples; +} + +/** A bounded prefix signature with blocked-state sign; neither labels nor repository identity enter the feature. */ +export function trackerFeature(example: TrackerExample): number { + const signature = Number.parseInt(hashJson([...example.prefix]).slice(0, 12), 16) / 0x1000000000000; + return (0.25 + signature / 4) * (example.prefix.at(-1) === "blocked" ? -1 : 1); +} diff --git a/docs/durable-systemone-validation.md b/docs/durable-systemone-validation.md index 7188a1f9..b8b7cdf0 100644 --- a/docs/durable-systemone-validation.md +++ b/docs/durable-systemone-validation.md @@ -140,7 +140,7 @@ Trainer selection uses `parseLoopTrainer`/`parseLoopProgramme`; bandit replay us ## Acceptance and limits -`npm run test:live` runs two real generations on synthetic PM items, checks changed +`npm run test:live:systemone` runs two real generations on synthetic PM items, checks changed checkpoints and successor collection, and prints per-generation accuracy/ECE, conditional held-out means, reported tokens, endpoint latency and wall time. `SYSTEMONE_BASE_URL` and `SYSTEMONE_MODEL` override the loopback service and diff --git a/docs/meta-live-evidence.json b/docs/meta-live-evidence.json new file mode 100644 index 00000000..7d76cb6a --- /dev/null +++ b/docs/meta-live-evidence.json @@ -0,0 +1,591 @@ +{ + "format": "pm-rl/meta-live-evidence/1", + "command": "npm run test:live", + "dataset": { + "format": "pm-rl/tracker-dataset/1", + "task": "terminal-disposition", + "seed": 42, + "sources": [ + { + "repo": "unbraind/pm-brand", + "commit": "7ad0970d96a20c24b8dbd9e0dcd1efeb8b4d5cc1", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-csv", + "commit": "31f968c5d63ac471f8df4495087c15f1809ca4d7", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-beads", + "commit": "8919a250feb3ebb51b9aa3288f6351de1f150c70", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-gantt-chart", + "commit": "57562e04a4c35bbb9e408b1d33605f61887375af", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-rust", + "commit": "6d519ecc40f5978f18e0cd546cce322fa67fc835", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-changelog", + "commit": "4a2e6330b0180b103c28d90a98bc731d326b1ef7", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-todos", + "commit": "aed7f7da9c9f960623f89f31a46b0a0815ae7b1e", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-jira", + "commit": "007d78e04c33d07eeddb8c32e23f88b6f4334fd0", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-presets", + "commit": "eea1037e0b9bf5c84fdee1e7617efa4bd42cfe2d", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-slack", + "commit": "0372d4ec234cefd9209843c2f9c8a418fef41d56", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-ts-starter", + "commit": "1236759ebce60a3b663d9715afae1354e64c1c15", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-ops", + "commit": "53bb64924d8affa6c55dd5c0b54f4fd6c971742b", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-graph", + "commit": "ef2caae43446d0103761581abd5a2a2b3a40528d", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-context", + "commit": "cc12869326f7ece5f4643a9fae5b90de0e27ec3a", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-slack-standup", + "commit": "0b3c57b3b47b3297e140892ea537f20104b4c2a1", + "license": "MIT", + "role": "train" + }, + { + "repo": "unbraind/pm-rl", + "commit": "b255dfac6543ab178ab2720fad1de1ba49f91dd4", + "license": "MIT", + "role": "meta-validation" + }, + { + "repo": "unbraind/pm-ado", + "commit": "6e78685557536226ffc6edb822b127c9a4acacbc", + "license": "MIT", + "role": "meta-validation" + }, + { + "repo": "unbraind/pm-lint", + "commit": "434f6f75be626308dbff872cd43329c54893ca1e", + "license": "MIT", + "role": "meta-validation" + }, + { + "repo": "unbraind/pm-brief", + "commit": "5f7f2761d335ce2d39f747434afc2370eb47854b", + "license": "MIT", + "role": "meta-validation" + }, + { + "repo": "unbraind/pm-review", + "commit": "58ea2c294137f4e392931dad8bb0af4d054bbc50", + "license": "MIT", + "role": "meta-validation" + }, + { + "repo": "unbraind/pm-starter", + "commit": "be5fac027b1124def32c612dc2ca3b5496d29dd2", + "license": "MIT", + "role": "final-test" + }, + { + "repo": "unbraind/pm-linear", + "commit": "0b213fc998211734368514c13e65669a4ea389f2", + "license": "MIT", + "role": "final-test" + }, + { + "repo": "unbraind/pm-jev", + "commit": "9a61b98d9774367ca959ae2d3c6b5f0f36514476", + "license": "MIT", + "role": "final-test" + }, + { + "repo": "unbraind/pm-vcs", + "commit": "1efdf4b3ca0da7968e4df4041aab3b5a4574a9fa", + "license": "MIT", + "role": "final-test" + }, + { + "repo": "unbraind/pm-github", + "commit": "247b95e6214f687d0d838d1685cc0e99db664cd6", + "license": "MIT", + "role": "final-test" + } + ], + "omitted_sources": [ + { + "repo": "unbraind/pm-swarm", + "commit": "10058499099a57900592205b6b414c98874067a6", + "reason": "no_prefixed_terminal_transition" + } + ], + "splits": { + "train": { + "digest": "2c869680ad763e3b0b60df14961be6450d929a020793097725449db9a476b95d", + "count": 1023 + }, + "inner-held-out": { + "digest": "7b14a572a1eba84202fb1b80af2bc8393569395482e49adbb530fe829fdca701", + "count": 145 + }, + "meta-validation": { + "digest": "789b975b4ec90353d2bfa839ff65c033f2996acd84cedfe25815717635cb8720", + "count": 214 + }, + "final-test": { + "digest": "e47eacd557d0827f487b71019f8820e84b8a41a2727baa533239acf4ca97f4de", + "count": 385 + } + }, + "digest": "a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c" + }, + "report": { + "initial": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.25, + "steps": 2, + "batch": 128, + "temperature": 1, + "correct_weight": 1, + "incorrect_weight": 0, + "selection": "all", + "curriculum": "forward" + }, + "digest": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae" + }, + "weight": 0, + "checkpoint": "sha256:17493680209cdf2fc86126ff2ad0b7bb6063ae24ce00f28f931224bb5ab2fd11" + }, + "incumbent": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.25, + "steps": 2, + "batch": 128, + "temperature": 1, + "correct_weight": 1, + "incorrect_weight": 0, + "selection": "all", + "curriculum": "forward" + }, + "digest": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae" + }, + "weight": 0, + "checkpoint": "sha256:17493680209cdf2fc86126ff2ad0b7bb6063ae24ce00f28f931224bb5ab2fd11" + }, + "generations": [ + { + "generation": 1, + "proposer": "seeded", + "candidates": [ + { + "candidate": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.9453377161710523, + "steps": 1, + "batch": 210, + "temperature": 1.5145122369285673, + "correct_weight": 0.7784251609118655, + "incorrect_weight": 0.12950040469877422, + "selection": "balanced", + "curriculum": "forward" + }, + "digest": "sha256:800886e9f4cd5b02c1ec5dacf8dd127649090ad0a14b8e70656df49ec5031b45" + }, + "weight": 0, + "checkpoint": "sha256:17493680209cdf2fc86126ff2ad0b7bb6063ae24ce00f28f931224bb5ab2fd11" + }, + "incumbent": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "score": { + "mean": 0.5, + "samples": 214, + "context": "789b975b4ec90353d2bfa839ff65c033f2996acd84cedfe25815717635cb8720" + }, + "gain": 0, + "gain_lower_bound": -0.21778781183411927, + "verdict": { + "decision": "refuse", + "code": "no_statistical_improvement", + "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.391106 does not beat incumbent upper bound 0.608894 by the effect threshold 0.01 (margin -0.227788). The candidate regressed: its mean is not above the incumbent's mean." + } + }, + { + "candidate": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.3441913548461162, + "steps": 2, + "batch": 175, + "temperature": 1.5323257620912045, + "correct_weight": 0.964415607159026, + "incorrect_weight": 0.0032701820600777864, + "selection": "all", + "curriculum": "reverse" + }, + "digest": "sha256:45113586500fd8a5a6f9460ef6fa902dace8faaba2d3fc69791c9bfdfc52fe56" + }, + "weight": 0, + "checkpoint": "sha256:17493680209cdf2fc86126ff2ad0b7bb6063ae24ce00f28f931224bb5ab2fd11" + }, + "incumbent": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "score": { + "mean": 0.5, + "samples": 214, + "context": "789b975b4ec90353d2bfa839ff65c033f2996acd84cedfe25815717635cb8720" + }, + "gain": 0, + "gain_lower_bound": -0.21778781183411927, + "verdict": { + "decision": "refuse", + "code": "no_statistical_improvement", + "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.391106 does not beat incumbent upper bound 0.608894 by the effect threshold 0.01 (margin -0.227788). The candidate regressed: its mean is not above the incumbent's mean." + } + } + ], + "promoted": null + }, + { + "generation": 2, + "proposer": "seeded", + "candidates": [ + { + "candidate": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.047517832086887216, + "steps": 1, + "batch": 138, + "temperature": 1.6416413390543312, + "correct_weight": 0.8013304566266015, + "incorrect_weight": 0.0981751901563257, + "selection": "all", + "curriculum": "reverse" + }, + "digest": "sha256:4a48567235f1fbca4e4a04c4b75ee3ac9586b613ea89641db727a03ef1c8c055" + }, + "weight": 0, + "checkpoint": "sha256:17493680209cdf2fc86126ff2ad0b7bb6063ae24ce00f28f931224bb5ab2fd11" + }, + "incumbent": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "score": { + "mean": 0.5, + "samples": 214, + "context": "789b975b4ec90353d2bfa839ff65c033f2996acd84cedfe25815717635cb8720" + }, + "gain": 0, + "gain_lower_bound": -0.21778781183411927, + "verdict": { + "decision": "refuse", + "code": "no_statistical_improvement", + "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.391106 does not beat incumbent upper bound 0.608894 by the effect threshold 0.01 (margin -0.227788). The candidate regressed: its mean is not above the incumbent's mean." + } + }, + { + "candidate": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.12488762147491797, + "steps": 1, + "batch": 96, + "temperature": 1.288743358803913, + "correct_weight": 0.7978050141828135, + "incorrect_weight": 0.004633317003026605, + "selection": "all", + "curriculum": "forward" + }, + "digest": "sha256:55539a90ca0580324861929b151e11ad8a6b8d4b0c50f3832c7c2ccf511ada8f" + }, + "weight": 0, + "checkpoint": "sha256:17493680209cdf2fc86126ff2ad0b7bb6063ae24ce00f28f931224bb5ab2fd11" + }, + "incumbent": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "score": { + "mean": 0.5, + "samples": 214, + "context": "789b975b4ec90353d2bfa839ff65c033f2996acd84cedfe25815717635cb8720" + }, + "gain": 0, + "gain_lower_bound": -0.21778781183411927, + "verdict": { + "decision": "refuse", + "code": "no_statistical_improvement", + "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.391106 does not beat incumbent upper bound 0.608894 by the effect threshold 0.01 (margin -0.227788). The candidate regressed: its mean is not above the incumbent's mean." + } + } + ], + "promoted": null + } + ], + "final_test": { + "before": { + "mean": 0.5142857142857142, + "samples": 385, + "context": "e47eacd557d0827f487b71019f8820e84b8a41a2727baa533239acf4ca97f4de" + }, + "after": { + "mean": 0.5142857142857142, + "samples": 385, + "context": "e47eacd557d0827f487b71019f8820e84b8a41a2727baa533239acf4ca97f4de" + } + }, + "dataset": "a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c" + }, + "dataset_build_and_controller_elapsed_ms": 93734.67408900001 +} diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md new file mode 100644 index 00000000..afb55116 --- /dev/null +++ b/docs/meta-recursive.md @@ -0,0 +1,134 @@ +# Meta-recursive recipe improvement + +`pm rl dataset build --from-trackers +--output ` builds the `terminal-disposition` environment from +committed public MIT tracker histories. GitHub visibility, license and commit +availability are checked before history blobs are read. Hosted data and the +pm-web, pm-gpt and pm-cli repositories are refused. The builder reads Git objects, +so uncommitted tracker changes never enter the dataset. Each example retains its +source repository, commit, opaque item identity, normalized lifecycle +prefix, and first terminal disposition (`completed` or `cancelled`). Imported +terminal snapshots without a prefix are omitted. Titles, comments, authors, +timestamps, local paths and close-reason prose are never copied. +Public repositories with no eligible prefixed terminal transitions are recorded +as omitted sources; at least three eligible repositories and four nonempty +compartments are required. + +Repositories are deterministically assigned to training, meta-validation and +final-test roles. Within training repositories, complete observable prefix groups +are assigned to either collection or inner held-out evaluation. Identical prefixes +cannot cross that inner boundary. The small logistic policy consumes a bounded +prefix signature with a sign for the last observed blocked state. This is a real +public-history environment and a deliberately limited numerical learner; it does +not demonstrate language-model training on tracker text. + +`pm rl meta run --file examples/meta-trackers.json --dataset +--approval ` executes or resumes the same programme. Its initial recipe +is a versioned content-addressed artifact. Numeric domains cover learning rate, +inner steps, batch, temperature and correct/incorrect reward weights. Categorical +domains cover balanced/all selection and forward/reverse curriculum. Steps bound +inner generations, each performing one real collected-batch REINFORCE update. +Temperature rescales the policy observation; reward weights affect collection +rewards only. Inner held-out and recipe-selection rewards remain exact match. +Every inner seed and generation names the recipe digest it used. + +The outer controller receives a fitted checkpoint from each bounded inner loop; +inner examples and scores stay in the evaluator. The proposer receives only the +incumbent knobs and a seeded candidate pool. It has no dataset coordinate or +held-out capability. With `--proposer decision-model`, a local `tev1:4b` ranks a +pool of bounded seeded recipes through the existing System One calibration +adapter. Missing, remote-backed or malformed models fall back to the original +seeded recipes. This is local proposal inference, bounded by request count and a +five-second timeout per HTTP request, and not a claim that the decision model +itself is trained. The default proposer makes no inference requests. +An intent is persisted before the first metadata or inference request. A response +lost before its completion receipt causes seeded fallback on resume; it cannot +spend another inference allowance. Completed proposal receipts replay verbatim. + +One **existing** Decision must contain `permitted_promotions`, `resource_budget` +and `meta_budget`. Search never creates, updates or enlarges it. Before fitting, +an SDK workspace transaction reserves worst-case collection samples, proposal +requests and recipe-promotion slots against all programmes using that Decision. +These conservative reservations remain held after failure or cancellation. +Each inner fit also uses the existing atomic process resource reservation, +measured completion receipt and settlement. Search cannot spend above either +allowance. The packaged process trainer is the only selectable meta trainer. + +Create a Decision from [the bounded approval example](../examples/meta-approval.md) +and supply its returned item id: + +```sh +pm create Decision "Approve bounded recipe search" --body-file examples/meta-approval.md +pm rl meta run tracker-search --file examples/meta-trackers.json --dataset --approval +``` + +The approval's identity and complete spec digest are immutable programme inputs. +Outer accounting reads certified metadata, then opens only stable reservation +identities; proposal recovery opens only its exact attempt record. An unrelated +item body or a renamed title cannot change the approved allocation. + +The existing fail-closed `decidePromotion` gate compares exact-match rewards on +meta-validation repositories. Sample counts are distinct examples, not repeated +rollouts. Confidence is allocated across all planned comparisons; the programme's +effect threshold and minimum sample count are fixed. A proxy-only gain cannot +promote a recipe. Among eligible candidates, the largest conservative lower gain +bound wins. A refusal retains the incumbent and still permits the next bounded +meta-generation. No successful candidate is required for acceptance. + +Meta-validation is an adaptive selection set. Per-example Hoeffding bounds retain +the existing gate's independent bounded-sample assumption; correlated items in a +repository limit population-level statistical interpretations. An untouched +final-test repository split is opened only after every recipe selection is +committed, and reports initial versus final policy on the same seeded exact-match +stream. Its score never proposes or promotes a recipe. These are controller +capability boundaries within the trusted local evaluator, not OS access controls +against arbitrary code running as the evaluator's user. + +Outer phases use the inner controller's verified process identity, shared Git +worktree launch authority, owner lease, phase fencing and digested completion +receipts. An interrupted fit re-enters the same inner programme, adopting its +completed steps and resource reservation. A completed outer phase adopts its +receipt. Inputs, approval or receipt drift refuse resume. Cancellation stops at a +durable boundary; external fits retain their existing terminal-cancellation +semantics. A new invocation of the same `meta run` command resumes the programme. +The 15-minute whole-run watchdog also applies to `npm run test:live`. + +The synthetic committed fixture and real temporary SDK trackers exercise this +contract. `npm run test:live` builds the actual public dataset at run time, executes +two meta-generations with two candidates each, and retains complete programme, +dataset, tracker and result evidence in ignored runtime state. The older System +One acceptance remains available as `npm run test:live:systemone`. Releases remain +disabled. + +## Measured live acceptance + +`npm run test:live` completed two meta-generations with two candidates each over +25 verified public MIT repositories. One further verified repository had no +eligible prefixed terminal events and is recorded as omitted. The dataset contains +1,023 training, 145 inner held-out, 214 meta-validation and 385 final-test examples +(1,767 total). Repository roles contain 15 training, five meta-validation and five +final-test repositories. Source commits, split digests, full recipes and verdicts +are retained in [the public evidence envelope](meta-live-evidence.json). + +The incumbent recipe is +`sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae`: +learning rate 0.25, two steps, batch 128, temperature 1, correct/incorrect weights +1/0, all examples and forward curriculum. The numerical learner's accepted +checkpoint remained the seed; the trained candidates did not pass inner promotion. +Outer recipe selection therefore measured each resulting policy against that +same accepted incumbent. + +| Meta generation | Candidate recipe digest prefix | Exact-match score | Gain | Lower gain bound | Verdict | +| --- | --- | ---: | ---: | ---: | --- | +| 1 | `800886e9f4cd` | 107/214 = 0.5 | 0 | -0.21778781183411927 | refuse | +| 1 | `45113586500f` | 107/214 = 0.5 | 0 | -0.21778781183411927 | refuse | +| 2 | `4a48567235f1` | 107/214 = 0.5 | 0 | -0.21778781183411927 | refuse | +| 2 | `55539a90ca05` | 107/214 = 0.5 | 0 | -0.21778781183411927 | refuse | + +The declared confidence is 0.95, allocated across four comparisons as 0.9875 per +comparison. The existing gate retains effect threshold 0.01, minimum ten samples, +and reward bounds [0,1]. Each side's Hoeffding half-width is +0.10889390591705964. No recipe was promoted in either generation. The final-test +score was **198/385 = 0.5142857142857142 before and after**. No real-data recipe +improvement is claimed, and the gate was not relaxed. Dataset build plus controller +execution took 93,734.674089 ms inside the command's unchanged 15-minute watchdog. diff --git a/examples/meta-approval.md b/examples/meta-approval.md new file mode 100644 index 00000000..28eb0de4 --- /dev/null +++ b/examples/meta-approval.md @@ -0,0 +1,24 @@ +# Bounded recipe search approval + +This example grants one two-generation search with two candidates per generation. +The outer controller reserves its declared worst-case plan once. Inner process +fits reserve and settle their measured resources under this same Decision. +Proposal calls include local model inventory and inference requests. + +```json +{ + "permitted_promotions": 10, + "resource_budget": { + "training_steps": 10, + "wall_ms": 300000, + "storage_bytes": 40960, + "compute_units": 300000, + "tokens": 0 + }, + "meta_budget": { + "training_samples": 2560, + "proposal_calls": 4, + "recipe_promotions": 2 + } +} +``` diff --git a/examples/meta-trackers.json b/examples/meta-trackers.json new file mode 100644 index 00000000..03ff883f --- /dev/null +++ b/examples/meta-trackers.json @@ -0,0 +1,71 @@ +{ + "initial_recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.25, + "steps": 2, + "batch": 128, + "temperature": 1, + "correct_weight": 1, + "incorrect_weight": 0, + "selection": "all", + "curriculum": "forward" + }, + "digest": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae" + }, + "seed": 42, + "meta_generations": 2, + "candidates": 2, + "timeout_ms": 840000, + "criterion": { + "confidence": 0.95, + "minSamples": 10, + "effectThreshold": 0.01 + }, + "maximum_gap": 0.3, + "evaluation_samples": 40000, + "adapter": { + "kind": "process-bandit", + "allowance": { + "training_steps": 1, + "wall_ms": 30000, + "storage_bytes": 4096, + "compute_units": 30000, + "tokens": 0 + } + } +} diff --git a/index.ts b/index.ts index fce4e5b7..8aed71c9 100644 --- a/index.ts +++ b/index.ts @@ -150,6 +150,12 @@ export { } from "./lm.ts"; export { decidePromotion, hoeffdingEpsilon, parsePromotionCriterion, parsePromotionEvidence, type PromotionCriterion, type PromotionDecision, type PromotionEvidence, type PromotionGateInput } from "./promotion.ts"; +export { recipeArtifact, parseRecipe, seededRecipes, INITIAL_RECIPE, RECIPE_BOUNDS, type Recipe, type RecipeKnobs } from "./recipe.ts"; +export { buildTrackerDataset, readTrackerDataset, readTrackerSplit, type TrackerDataset, type TrackerExample } from "./dataset.ts"; +export { runRlMeta, parseMetaConfig, type MetaConfig, type MetaRequest, type MetaReport } from "./meta.ts"; + +import { buildTrackerDataset } from "./dataset.ts"; +import { runRlMeta, parseMetaConfig, type MetaReport } from "./meta.ts"; import { trainLmStep, evaluateLmStep, lmTrainingJson, restoreLmTraining, restoreLmGeneration, serializeLmCheckpoint, @@ -3268,6 +3274,22 @@ async function durableLoopStep(client: PmClient, lease: ControllerLease, id: str }); } +/** Durable step executor shared by inner and outer controllers. */ +export type RlDurableStep = (key: string, input: JsonValue, execute: () => Promise) => Promise; + +/** Reuse the inner loop's owner lease, worktree authority, phase fencing and digested receipts for recipe search. */ +export async function withRlController(client: PmClient, coordinates: WorkspaceCoordinates, id: string, signal: AbortSignal, execute: (step: RlDurableStep) => Promise): Promise { + const lease = await acquireControllerLease(client, coordinates, { id, approval: "meta", config: null, signal }, `${id}-step-programme`); + try { + return await execute(async (key, input, operation) => { + signal.throwIfAborted(); + return (await durableLoopStep(client, lease, id, key, input, operation)).value; + }); + } finally { + await lease.release(); + } +} + /** Read one run's decoded metric events in order, without mutating anything. */ async function readRunMetricEvents(client: PmClient, runId: string): Promise { return readSeries((await readCompleteNotes(client, runId)).map((note) => note.text)).events; @@ -4140,6 +4162,31 @@ async function runLoop(context: CommandHandlerContext): Promise return { action: "rl-loop-run", id, details: loopCommandDetails(context, report) }; } +/** Build a commit-pinned public tracker dataset through the installed command contract. */ +async function buildDatasetCommand(context: CommandHandlerContext): Promise { + const first = stringOption(context, "from_trackers")!; + const directories = [first, ...context.args]; + const dataset = buildTrackerDataset(directories, stringOption(context, "output")!, Number(stringOption(context, "seed", false) ?? "42")); + return { action: "rl-dataset-build", details: { ...dataset } }; +} + +/** Execute or resume recipe search with the same cancellation boundaries as the inner loop. */ +async function runMetaCommand(context: CommandHandlerContext): Promise { + const id = requiredArgument(context, "a meta-loop id"); + const cancellation = installCancellationSignals(); + let report: MetaReport; + try { + report = await runRlMeta(clientFor(context), { pmRoot: context.pm_root, author: authorFor(context) }, { + id, config: parseMetaConfig(readJsonFile(stringOption(context, "file")!, "Meta configuration")), + dataset: stringOption(context, "dataset")!, approval: stringOption(context, "approval")!, + proposer: (stringOption(context, "proposer", false) ?? "seeded") as "seeded" | "decision-model", signal: cancellation.controller.signal, + }); + } finally { + removeCancellationSignals(cancellation.handlers); + } + return { action: "rl-meta-run", id, details: { ...report } }; +} + /** Resume one interrupted loop through the public command surface. */ async function resumeLoopCommand(context: CommandHandlerContext): Promise { const id = requiredArgument(context, "a loop id"); @@ -4798,6 +4845,17 @@ async function showTransferGap(context: CommandHandlerContext): Promise canonicalJson({ feature: example.feature, rewards: [...example.rewards] }))); if (processAdapter.kind === "compose-lm") expectedFail("Bandit requires a bandit process adapter.", "process_invalid_adapter"); if (datasets.training.some((example) => heldOut.has(canonicalJson({ feature: example.feature, rewards: [...example.rewards] })))) expectedFail("Process training and held-out content overlap.", "process_dataset_overlap"); } const config: LoopConfig = { + ...(recipe === undefined ? {} : { recipe }), ...(processAdapter === undefined ? {} : { process: processAdapter }), environmentName, environmentVersion, @@ -225,6 +233,7 @@ export function parseLoopConfig(raw: JsonValue): LoopConfig { trainingDigest: datasets.trainingDigest, evaluationDigest: datasets.evaluationDigest, digest: loopDigest({ + ...(recipe === undefined ? {} : { recipe: recipe.digest }), ...(processAdapter === undefined ? {} : { adapter: processAdapter as unknown as JsonValue }), format: "pm-rl/loop-programme/1", environment: { name: environmentName, version: environmentVersion }, @@ -447,6 +456,7 @@ export function loopPromotionScores(config: LoopConfig, step: LoopStepConfig, ge */ export function generationTrainingConfig(config: LoopConfig, step: LoopStepConfig, generation: number, receipt: BanditGeneration): JsonValue { return { + ...(config.recipe === undefined ? {} : { recipe: config.recipe.digest }), format: LOOP_GENERATION_FORMAT, generation, learning_rate: step.learningRate, @@ -476,10 +486,12 @@ export function generationTrainingConfig(config: LoopConfig, step: LoopStepConfi */ export function seedTrainingConfig(config: LoopConfig): JsonValue { return { + ...(config.recipe === undefined ? {} : { recipe: config.recipe.digest }), format: LOOP_SEED_FORMAT, programme: config.digest, initial_weight: config.initialWeight, configuration: { + ...(config.recipe === undefined ? {} : { recipe: config.recipe as unknown as JsonValue }), ...(config.process === undefined ? {} : { adapter: config.process as unknown as JsonValue }), environment: { name: config.environmentName, version: config.environmentVersion }, training: config.training.map(jsonExample), @@ -569,6 +581,8 @@ export function parseLoopProgramme(raw: JsonValue): LoopProgramme { * deterministic replay before advancing the chain. */ export interface StoredLoopGeneration { + /** Recipe digest whose knobs governed this generation, when declared by the programme. */ + readonly recipeDigest?: string; /** One-based generation number, matching the recomputed receipt. */ readonly generation: number; /** The derived learning rate this generation ran under. */ @@ -632,6 +646,7 @@ export function parseStoredLoopGeneration(value: JsonValue, source: string): Sto expectedFail(`${source} candidate_weight is outside the stable policy bound [-20, 20]; the persisted checkpoint is invalid.`, "loop_invalid_checkpoint"); } const stored: StoredLoopGeneration = { + ...(record["recipe"] === undefined ? {} : { recipeDigest: storedCheckpointDigest(record, "recipe", source, "loop_invalid_checkpoint") }), generation, learningRate: storedCheckpointNumber(record, "learning_rate", source, "loop_invalid_training_config"), evaluationSamples: storedCheckpointNumber(record, "evaluation_samples", source, "loop_invalid_training_config"), @@ -684,6 +699,7 @@ export function verifyStoredLoopGeneration(config: LoopConfig, step: LoopStepCon expectedFail(`Loop generation ${generation} records candidate checkpoint ${stored.candidateCheckpoint}, which does not match the digest of its own persisted weight; the persisted checkpoint is invalid.`, "loop_invalid_checkpoint", EXIT_CODE.CONFLICT); } const expected: Array<[string, unknown, unknown]> = [ + ["recipe", stored.recipeDigest, config.recipe?.digest], ["generation", stored.generation, generation], ["learning_rate", stored.learningRate, step.learningRate], ["evaluation_samples", stored.evaluationSamples, step.evaluationSamples], diff --git a/manifest.json b/manifest.json index 643eb918..51a18a97 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "pm-rl", "version": "2026.7.31", - "description": "Reinforcement-learning programme management on the pm SDK. Content-addressed environments and benchmarks keep runs and evaluations attributable; fail-closed leaderboards refuse mixed environments and contaminated suites. Commands: `pm rl env register/list/show`, `pm rl benchmark register`, `pm rl eval record`, `pm rl leaderboard`, `pm rl run start/log/show/finish`, `pm rl generation register/promote/show`, `pm rl lineage`, `pm rl invalidate`, and `pm rl compare`.", + "description": "Reinforcement-learning programme management on the pm SDK. Content-addressed environments and benchmarks keep runs and evaluations attributable; fail-closed leaderboards refuse mixed environments and contaminated suites. Commands: `pm rl env register/list/show`, `pm rl benchmark register`, `pm rl eval record`, `pm rl leaderboard`, `pm rl run start/log/show/finish`, `pm rl generation register/promote/show`, `pm rl lineage`, `pm rl invalidate`, and `pm rl compare`. Bounded recipe search: `pm rl dataset build` and `pm rl meta run`.", "author": "@unbraind", "entry": "./dist/index.js", "priority": 50, diff --git a/meta.ts b/meta.ts new file mode 100644 index 00000000..db05db6f --- /dev/null +++ b/meta.ts @@ -0,0 +1,267 @@ +/** Durable recipe search over sealed tracker compartments, using the existing trainer and promotion gate. */ +import assert from "node:assert/strict"; +import type { PmClient } from "@unbrained/pm-cli/sdk/core"; +import { certifyCompleteListResult } from "@unbrained/pm-cli/sdk/runtime"; +import { hashJson, commitProcessTransaction, readCompleteLoopItem, withRlController, type JsonValue, type RlDurableStep } from "./index.ts"; +import { openTrackerEnvironment } from "./tracker-environment.ts"; +import { parseProcessAdapter, type ProcessAdapter, type ProcessCoordinates } from "./process.ts"; +import { decidePromotion, hoeffdingEpsilon, parsePromotionCriterion, type PromotionCriterion, type PromotionEvidence, type PromotionDecision } from "./promotion.ts"; +import { parseRecipe, seededRecipes, RECIPE_BOUNDS, type Recipe } from "./recipe.ts"; +import { requestSystemOneDecision, calibratedProbabilities } from "./systemone.ts"; + +/** Immutable programme limits; recipes cannot tune evaluation criteria or approval identity. */ +export interface MetaConfig { + readonly initial_recipe: Recipe; + readonly seed: number; + readonly meta_generations: number; + readonly candidates: number; + readonly timeout_ms: number; + readonly criterion: PromotionCriterion; + readonly maximum_gap: number; + readonly evaluation_samples: number; + readonly adapter: ProcessAdapter; +} +/** A fitted policy is interpreted with the temperature of the recipe that produced it. */ +export interface RecipePolicy { readonly recipe: Recipe; readonly weight: number; readonly checkpoint: string } +/** Exact-match evidence counts distinct examples, rather than repeated pseudo-replications. */ +export interface TrackerScore { readonly mean: number; readonly samples: number; readonly context: string } +/** Each comparison retains the actual gate, observed gain and conservative lower confidence bound. */ +export interface MetaComparison { + readonly candidate: RecipePolicy; + readonly incumbent: string; + readonly score: TrackerScore; + readonly gain: number; + readonly gain_lower_bound: number; + readonly verdict: PromotionDecision; +} +/** Final reports expose selection evidence and only then the untouched final-test comparison. */ +export interface MetaReport { + readonly initial: RecipePolicy; + readonly incumbent: RecipePolicy; + readonly generations: readonly { readonly generation: number; readonly proposer: string; readonly candidates: readonly MetaComparison[]; readonly promoted: string | null }[]; + readonly final_test: { readonly before: TrackerScore; readonly after: TrackerScore }; + readonly dataset: string; +} +/** Public command request; filesystem coordinates never enter recipe or programme identities. */ +export interface MetaRequest { + readonly id: string; + readonly config: MetaConfig; + readonly dataset: string; + readonly approval: string; + readonly proposer: "seeded" | "decision-model"; + readonly signal?: AbortSignal; + /** Loopback endpoint override for real HTTP acceptance fixtures. @internal */ + readonly decisionEndpoint?: string; + /** Observe committed boundaries for real cancellation and crash drills. @internal */ + readonly onStep?: (key: string) => void | Promise; +} + +/** Parse all hard bounds before acquiring a controller or reading a dataset compartment. */ +export function parseMetaConfig(value: unknown): MetaConfig { + const config = value as MetaConfig; + const initial = parseRecipe(config.initial_recipe); + for (const [key, max] of [["seed", 0xffff_ffff], ["meta_generations", 10], ["candidates", 8], ["timeout_ms", 900_000], ["evaluation_samples", 100_000]] as const) { + const minimum = key === "seed" ? 0 : 1; + assert.ok(Number.isInteger(config[key]) && config[key] >= minimum && config[key] <= max, `meta_bound: ${key}`); + } + const criterion = parsePromotionCriterion(config.criterion); + assert.ok(criterion.effectThreshold > 0 && Number.isFinite(config.maximum_gap) && config.maximum_gap >= 0 && config.maximum_gap <= 1, "meta_criterion"); + const adapter = parseProcessAdapter(config.adapter); + assert.equal(adapter.kind, "process-bandit", "meta_packaged_process_required"); + return { ...config, initial_recipe: initial, criterion, adapter }; +} + +/** Read the pre-existing Decision, binding both promotion and resource allowances to its complete body. */ +async function metaApproval(client: PmClient, id: string): Promise<{ id: string; digest: string; limits: Record }> { + const item = await readCompleteLoopItem(client, id); + assert.equal(item.item.type, "Decision", "meta_approval_required"); + const fence = /```json\n([\s\S]+?)\n```/.exec(String(item.item.body)); + assert.ok(fence !== null, "meta_approval_spec"); + const spec = JSON.parse(fence[1]) as { meta_budget: Record }; + assert.ok(spec.meta_budget !== null && typeof spec.meta_budget === "object", "meta_budget_required"); + for (const key of ["training_samples", "proposal_calls", "recipe_promotions"]) { + assert.ok(Number.isSafeInteger(spec.meta_budget[key]) && spec.meta_budget[key] >= 0, "meta_budget_bound"); + } + return { id: String(item.item.id), digest: hashJson(spec as unknown as JsonValue), limits: spec.meta_budget }; +} + +/** Parse reservation envelopes independent of JSON spacing; unrelated text cannot charge or conceal an allowance. */ +export function metaReservation(body: string): { id: string; approval: string; charge: Record } | null { + if (!body.includes("pm-rl/meta-reservation/1")) return null; + try { + const record = JSON.parse(body) as { format: string; id: string; approval: string; charge: Record }; + return record.format === "pm-rl/meta-reservation/1" ? record : null; + } catch { return null; } +} + +/** Atomically hold worst-case search allowances once; interrupted programmes retain their reservation. */ +async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, request: MetaRequest, binding: string): Promise { + const { config } = request; + const charge = { training_samples: (1 + config.meta_generations * config.candidates) * RECIPE_BOUNDS.steps[1] * RECIPE_BOUNDS.batch[1], + proposal_calls: request.proposer === "decision-model" ? 2 * config.meta_generations : 0, recipe_promotions: config.meta_generations }; + const key = `${request.id}-reservation`; + await commitProcessTransaction({ ...coordinates, transactionId: `${key}-reserve`, steps: [{ id: "reserve", + async inspect() { + const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); + const previous = items.items.find((item) => item.type === "Decision" && (item.id === key || item.id.endsWith(`-${key}`))); + if (previous === undefined) return { state: "pending" }; + const record = JSON.parse(String((await readCompleteLoopItem(client, previous.id)).item.body)) as { format: string; id: string; binding: string; approval: string; charge: JsonValue }; + assert.equal(record.binding, binding, "meta_reservation_drift"); + assert.equal(record.format, "pm-rl/meta-reservation/1", "meta_reservation_drift"); + assert.equal(record.id, key, "meta_reservation_drift"); + assert.equal(record.approval, (await metaApproval(client, request.approval)).id, "meta_reservation_drift"); + assert.equal(hashJson(record.charge), hashJson(charge), "meta_reservation_drift"); + return { state: "applied" }; + }, + async apply() { + const approval = await metaApproval(client, request.approval); + const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); + const charges: Record[] = []; + for (const item of items.items.filter((entry) => entry.type === "Decision" && entry.id.endsWith("-reservation"))) { + const record = metaReservation(String((await readCompleteLoopItem(client, item.id)).item.body)); + if (record !== null && (item.id === record.id || item.id.endsWith(`-${record.id}`)) && record.approval === approval.id) { + for (const key of ["training_samples", "proposal_calls", "recipe_promotions"]) { + assert.ok(Number.isSafeInteger(record.charge[key]) && record.charge[key] >= 0, "meta_reservation_charge"); + } + charges.push(record.charge); + } + } + for (const key of ["training_samples", "proposal_calls", "recipe_promotions"] as const) { + const total = charges.reduce((sum, entry) => sum + entry[key], charge[key]); + assert.ok(Number.isSafeInteger(total) && total <= approval.limits[key], `meta_budget_exhausted: ${key}`); + } + await client.create({ id: key, type: "Decision", title: "Reserved bounded recipe search", body: JSON.stringify({ format: "pm-rl/meta-reservation/1", id: key, binding, approval: approval.id, charge }) }); + }, + // Conservative reservations survive transaction recovery and are never refunded by search itself. + async compensate() {}, + }] }); +} + +/** Numerical task helpers are shared with the sealed evaluator, without granting search a data reader. */ +export { recipeExamples, scoreTrackerPolicy } from "./tracker-environment.ts"; + +/** Apply the unchanged fail-closed statistical gate to recipe selection, never to proxy reward. */ +export function compareRecipes(candidate: RecipePolicy, incumbent: RecipePolicy, score: TrackerScore, baseline: TrackerScore, criterion: PromotionCriterion): MetaComparison { + /** Convert sealed exact-match measurements into the existing bounded-evidence contract. */ + const evidence = (policy: RecipePolicy, value: TrackerScore): PromotionEvidence => ({ generation: policy.recipe.digest, + objective: "terminal_disposition_exact_match", objective_version: "1", evaluation_context: value.context, + direction: "maximize", mean: value.mean, samples: value.samples, rewardBounds: [0, 1] }); + const verdict = decidePromotion({ candidate: evidence(candidate, score), incumbent: evidence(incumbent, baseline), criterion, + contaminationPath: null, expectedGeneration: candidate.recipe.digest }); + const gain = score.mean - baseline.mean; + const alpha = 1 - criterion.confidence; + return { candidate, incumbent: incumbent.recipe.digest, score, gain, + gain_lower_bound: gain - hoeffdingEpsilon(score.samples, 1, alpha) - hoeffdingEpsilon(baseline.samples, 1, alpha), verdict }; +} + +/** Select only a gate-approved recipe, preferring the largest conservative improvement and retaining an unchallenged incumbent. */ +export function recipeSuccessor(incumbent: RecipePolicy, candidates: readonly MetaComparison[]): { successor: RecipePolicy; promoted: string | null } { + const eligible = candidates.filter((candidate) => candidate.verdict.decision === "promote").sort((a, b) => b.gain_lower_bound - a.gain_lower_bound); + return { successor: eligible.length === 0 ? incumbent : eligible[0].candidate, promoted: eligible.length === 0 ? null : eligible[0].candidate.recipe.digest }; +} + +/** Optionally let the local calibrated decision adapter rank a seeded pool; unavailable models preserve seeded search. @internal */ +export async function proposeRecipes(request: Pick, incumbent: Recipe, generation: number, signal: AbortSignal): Promise<{ recipes: Recipe[]; proposer: string }> { + const pool = seededRecipes(incumbent, request.config.seed, generation, request.config.candidates); + if (request.proposer === "seeded") return { recipes: pool, proposer: "seeded" }; + const baseURL = request.decisionEndpoint ?? "http://127.0.0.1:11434"; + assert.ok(["127.0.0.1", "localhost", "[::1]"].includes(new URL(baseURL).hostname), "meta_local_proposer_required"); + try { + const response = await fetch(`${baseURL}/api/tags`, { signal: AbortSignal.any([signal, AbortSignal.timeout(5000)]) }); + const tags = await response.json() as { models: { name: string; remote_host?: string; remote_model?: string }[] }; + assert.ok(response.ok && tags.models.some((model) => model.name === "tev1:4b" && model.remote_host === undefined && model.remote_model === undefined), "meta_model_unavailable"); + const ranked = [...pool, ...seededRecipes(incumbent, request.config.seed ^ 0x85ebca6b, generation, request.config.candidates)]; + const criteria = Object.fromEntries(ranked.map((recipe) => [recipe.digest, JSON.stringify(recipe.knobs)])); + const result = await requestSystemOneDecision({ baseURL, model: "tev1:4b", timeoutMs: 5000 }, JSON.stringify({ incumbent: incumbent.knobs, generation }), + [{ name: "recipe", instructions: "Rank these bounded training recipes for terminal disposition prediction. No evaluation data is available.", criteria }], signal); + const probabilities = calibratedProbabilities(result.answers.recipe, 0, Object.fromEntries(ranked.map((recipe) => [recipe.digest, 0]))); + ranked.sort((a, b) => probabilities[b.digest] - probabilities[a.digest] || a.digest.localeCompare(b.digest)); + return { recipes: ranked.slice(0, request.config.candidates), proposer: "decision-model" }; + } catch { + signal.throwIfAborted(); + return { recipes: pool, proposer: "seeded:model-unavailable" }; + } +} + +/** Persist a single inference intent; an unresolved attempt resumes with seeded recipes instead of spending twice. @internal */ +export async function durableRecipeProposals(client: PmClient, id: string, request: Pick, incumbent: Recipe, generation: number, signal: AbortSignal): Promise<{ recipes: Recipe[]; proposer: string }> { + if (request.proposer === "seeded") return proposeRecipes(request, incumbent, generation, signal); + const key = `${id}-m${generation}-proposal-attempt`; + const binding = hashJson({ config: request.config as unknown as JsonValue, incumbent: incumbent.digest, generation, endpoint: request.decisionEndpoint ?? "http://127.0.0.1:11434" }); + const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); + const previous = items.items.find((item) => item.type === "Decision" && (item.id === key || item.id.endsWith(`-${key}`))); + if (previous !== undefined) { + const record = JSON.parse(String((await readCompleteLoopItem(client, previous.id)).item.body)) as { binding: string; state: string; result: { recipes: Recipe[]; proposer: string }; digest: string }; + assert.equal(record.binding, binding, "meta_proposal_drift"); + if (record.state === "complete") { + assert.equal(hashJson(record.result as unknown as JsonValue), record.digest, "meta_proposal_receipt"); + for (const recipe of record.result.recipes) parseRecipe(recipe); + return record.result; + } + assert.equal(record.state, "intent", "meta_proposal_state"); + return { recipes: seededRecipes(incumbent, request.config.seed, generation, request.config.candidates), proposer: "seeded:unresolved-model-attempt" }; + } + await client.create({ id: key, type: "Decision", title: "Bounded local recipe inference intent", body: JSON.stringify({ binding, state: "intent" }) }); + const result = await proposeRecipes(request, incumbent, generation, signal); + await client.update(key, { body: JSON.stringify({ binding, state: "complete", result, digest: hashJson(result as unknown as JsonValue) }) }); + return result; +} + +/** Search and promote recipes with one shared approval; completion receipts adopt inner jobs after interruption. */ +export async function runRlMeta(client: PmClient, coordinates: ProcessCoordinates, request: MetaRequest): Promise { + const config = parseMetaConfig(request.config); + assert.ok(request.proposer === "seeded" || request.proposer === "decision-model", "meta_proposer"); + const signal = request.signal === undefined ? AbortSignal.timeout(config.timeout_ms) : AbortSignal.any([request.signal, AbortSignal.timeout(config.timeout_ms)]); + const environment = openTrackerEnvironment(client, coordinates, request.dataset, config, request.approval); + const proposalRequest = { config, proposer: request.proposer, decisionEndpoint: request.decisionEndpoint }; + const approval = await metaApproval(client, request.approval); + const input = { format: "pm-rl/meta-programme/1", id: request.id, config: config as unknown as JsonValue, dataset: environment.digest, approval_id: approval.id, approval: approval.digest, + proposer: request.proposer, endpoint: request.decisionEndpoint ?? "http://127.0.0.1:11434" }; + const binding = hashJson(input); + return withRlController(client, coordinates, request.id, signal, async (durable) => { + /** Verify approval identity at every boundary, and notify observers only after the receipt is durable. */ + const step: RlDurableStep = async (key, value, execute) => { + assert.equal((await metaApproval(client, request.approval)).digest, approval.digest, "meta_budget_drift"); + const result = await durable(key, { binding, value }, execute); + await request.onStep?.(key); + return result; + }; + await step("programme", input, async () => { await reserveMeta(client, coordinates, request, binding); return input; }); + const initial = await step("initial", { recipe: config.initial_recipe.digest }, async () => + await environment.fit(config.initial_recipe, `${request.id}-initial`, signal) as unknown as JsonValue) as unknown as RecipePolicy; + const incumbents = [initial]; + const generations: MetaReport["generations"][number][] = []; + for (let generation = 1; generation <= config.meta_generations; generation += 1) { + const incumbent = incumbents.at(-1)!; + const proposals = await step(`m${generation}-proposals`, { incumbent: incumbent.recipe.digest }, async () => + await durableRecipeProposals(client, request.id, proposalRequest, incumbent.recipe, generation, signal) as unknown as JsonValue) as unknown as Awaited>; + const candidates: MetaComparison[] = []; + for (const [index, recipe] of proposals.recipes.entries()) { + const policy = await step(`m${generation}-c${index}`, { recipe: recipe.digest }, async () => + await environment.fit(recipe, `${request.id}-m${generation}-c${index}`, signal) as unknown as JsonValue) as unknown as RecipePolicy; + const comparison = await step(`m${generation}-score${index}`, { candidate: policy.checkpoint, incumbent: incumbent.recipe.digest }, async () => { + const { score, baseline } = environment.selection(policy, incumbent); + // Allocate family-wise error across all planned comparisons; search cannot relax the declared gate. + const criterion = { ...config.criterion, confidence: 1 - (1 - config.criterion.confidence) / (config.meta_generations * config.candidates) }; + return compareRecipes(policy, incumbent, score, baseline, criterion) as unknown as JsonValue; + }) as unknown as MetaComparison; + candidates.push(comparison); + } + const promoted = await step(`m${generation}-promote`, { incumbent: incumbent.recipe.digest, candidates: candidates as unknown as JsonValue }, async () => { + return recipeSuccessor(incumbent, candidates) as unknown as JsonValue; + }) as unknown as { successor: RecipePolicy; promoted: string | null }; + incumbents.push(promoted.successor); + generations.push({ generation, proposer: proposals.proposer, candidates, promoted: promoted.promoted }); + } + const incumbent = incumbents.at(-1)!; + const final = await step("final-test", { before: initial.checkpoint, after: incumbent.checkpoint, recipe: incumbent.recipe.digest }, async () => { + return environment.finalTest(initial, incumbent) as unknown as JsonValue; + }) as unknown as MetaReport["final_test"]; + const report: MetaReport = { initial, incumbent, generations, final_test: final, dataset: environment.digest }; + await step("complete", { report: report as unknown as JsonValue }, async () => { + await client.update(`${request.id}-step-programme`, { comment: [`Loop ${request.id} terminal report: bounded recipe search complete.`] }); + return { report: report as unknown as JsonValue }; + }); + return report; + }); +} diff --git a/package.json b/package.json index c05ef485..b2808926 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,13 @@ "dist/compose.*", "dist/process-lm.*", "dist/process-lm-trainer.*", - "lm-trainer.Dockerfile" + "lm-trainer.Dockerfile", + "dist/recipe.*", + "dist/dataset.*", + "dist/meta.*", + "docs/meta-recursive.md", + "docs/meta-live-evidence.json", + "dist/tracker-environment.*" ], "engines": { "node": ">=22.18.0" @@ -62,7 +68,8 @@ "prepare": "node scripts/prepare-merge-driver.ts", "merge:install": "pm merge install", "coverage": "npm run build && npm run build:test && node scripts/coverage-gate.ts", - "test:live": "node scripts/live-watchdog.ts" + "test:live": "node scripts/live-watchdog.ts meta", + "test:live:systemone": "node scripts/live-watchdog.ts" }, "coverageGate": { "sources": [ @@ -100,7 +107,10 @@ "test/process-loop.test.ts", "test/process-cli.test.ts", "test/compose.test.ts", - "test/lm-compose.test.ts" + "test/lm-compose.test.ts", + "test/recipe.test.ts", + "test/dataset.test.ts", + "test/meta.test.ts" ], "thresholds": { "statements": 100, @@ -181,7 +191,9 @@ "RECURSIVE_TRAINING.md", "docs/durable-systemone-validation.md", "docs/lm-adapter.md", - "docs/process-trainer.md" + "docs/process-trainer.md", + "docs/meta-recursive.md", + "docs/meta-live-evidence.json" ], "examples": [ "README.md", @@ -191,7 +203,8 @@ "examples/metrics.ndjson", "examples/loop-systemone.json", "examples/loop-lm.json", - "examples/loop-process.json" + "examples/loop-process.json", + "examples/meta-approval.md" ] } } diff --git a/recipe.ts b/recipe.ts new file mode 100644 index 00000000..5897c2b1 --- /dev/null +++ b/recipe.ts @@ -0,0 +1,70 @@ +/** Content-addressed search recipes; bounds are part of the artifact and cannot expand during search. */ +import assert from "node:assert/strict"; +import { hashJson, type JsonValue } from "./index.ts"; + +/** Numeric and categorical domains supported by the bounded tracker trainer. */ +export const RECIPE_BOUNDS = { + learning_rate: [0.01, 1], steps: [1, 2], batch: [16, 256], + temperature: [0.5, 2], correct_weight: [0.5, 1], incorrect_weight: [0, 0.25], + selection: ["all", "balanced"], curriculum: ["forward", "reverse"], +} as const; + +/** All tunable inputs to one inner programme, separate from immutable evaluation criteria. */ +export interface RecipeKnobs { + readonly learning_rate: number; + readonly steps: number; + readonly batch: number; + readonly temperature: number; + readonly correct_weight: number; + readonly incorrect_weight: number; + readonly selection: "all" | "balanced"; + readonly curriculum: "forward" | "reverse"; +} + +/** Versioned recipe identity binds every knob and its declared search domain. */ +export interface Recipe { + readonly format: "pm-rl/recipe/1"; + readonly bounds: typeof RECIPE_BOUNDS; + readonly knobs: RecipeKnobs; + readonly digest: string; +} + +/** Validate and canonically address a recipe without trusting a supplied digest. */ +export function recipeArtifact(knobs: RecipeKnobs): Recipe { + assert.deepEqual(Object.keys(knobs).sort(), Object.keys(RECIPE_BOUNDS).sort(), "recipe_knobs"); + for (const key of ["learning_rate", "steps", "batch", "temperature", "correct_weight", "incorrect_weight"] as const) { + const value = knobs[key]; + const [low, high] = RECIPE_BOUNDS[key]; + assert.ok(Number.isFinite(value) && value >= low && value <= high, `recipe_bound: ${key}`); + } + assert.ok(Number.isInteger(knobs.steps) && Number.isInteger(knobs.batch), "recipe_integer"); + assert.ok(RECIPE_BOUNDS.selection.includes(knobs.selection) && RECIPE_BOUNDS.curriculum.includes(knobs.curriculum), "recipe_category"); + const record = { format: "pm-rl/recipe/1" as const, bounds: RECIPE_BOUNDS, knobs: { ...knobs } }; + return { ...record, digest: `sha256:${hashJson(record as unknown as JsonValue)}` }; +} + +/** Reject altered domains, versions, unknown fields and mismatched content identities. */ +export function parseRecipe(value: unknown): Recipe { + const record = value as Recipe; + assert.ok(record !== null && typeof record === "object", "recipe_record"); + const recipe = recipeArtifact(record.knobs); + assert.equal(hashJson(value as JsonValue), hashJson(recipe as unknown as JsonValue), "recipe_identity"); + return recipe; +} + +/** Initial programme recipe: deliberately modest fits, exact reward, and no rebalancing. */ +export const INITIAL_RECIPE = recipeArtifact({ learning_rate: 0.25, steps: 2, batch: 128, temperature: 1, + correct_weight: 1, incorrect_weight: 0, selection: "all", curriculum: "forward" }); + +/** Propose bounded successors deterministically from the seed, generation and incumbent identity. */ +export function seededRecipes(incumbent: Recipe, seed: number, generation: number, count: number): Recipe[] { + assert.ok(Number.isInteger(count) && count >= 1 && count <= 8, "recipe_candidate_count"); + let state = Number.parseInt(hashJson({ seed, generation, incumbent: incumbent.digest }).slice(7, 15), 16); + /** Advance an unsigned LCG whose domain is independent of collection and evaluation. */ + const draw = (): number => { state = (Math.imul(state, 1664525) + 1013904223) >>> 0; return state / 0x100000000; }; + return Array.from({ length: count }, () => recipeArtifact({ + learning_rate: 0.01 + draw() * 0.99, steps: 1 + Math.floor(draw() * 2), batch: 16 + Math.floor(draw() * 241), + temperature: 0.5 + draw() * 1.5, correct_weight: 0.5 + draw() * 0.5, incorrect_weight: draw() * 0.25, + selection: draw() < 0.5 ? "all" : "balanced", curriculum: draw() < 0.5 ? "forward" : "reverse", + })); +} diff --git a/scripts/live-meta.ts b/scripts/live-meta.ts new file mode 100644 index 00000000..28dc8a4c --- /dev/null +++ b/scripts/live-meta.ts @@ -0,0 +1,86 @@ +/** Opt-in acceptance over real public fleet history, with a whole-run watchdog and retained local evidence. */ +import assert from "node:assert/strict"; +import { execFileSync } from "node:child_process"; +import { mkdirSync, mkdtempSync, readdirSync, writeFileSync } from "node:fs"; +import { join, relative, resolve } from "node:path"; +import { PmClient } from "@unbrained/pm-cli/sdk/core"; +import { init } from "@unbrained/pm-cli/sdk/runtime"; +import { buildTrackerDataset } from "../dataset.ts"; +import { runRlMeta, type MetaConfig, type MetaReport } from "../meta.ts"; +import { INITIAL_RECIPE } from "../recipe.ts"; +import { isMainInvocation } from "./script-launcher.ts"; +import { LIVE_WORKER_DEADLINE_MS, LIVE_WORKER_TIMEOUT_ENV } from "./live-watchdog.ts"; + +/** Discover only immediate fleet checkouts, verifying visibility before allowing history reads. */ +export function publicTrackerDirectories(fleet: string): string[] { + const directories: string[] = []; + for (const entry of readdirSync(fleet, { withFileTypes: true })) { + if (!entry.isDirectory() || !entry.name.startsWith("pm-") || ["pm-web", "pm-gpt", "pm-cli"].includes(entry.name)) continue; + const metadata = JSON.parse(execFileSync("gh", ["repo", "view", `unbraind/${entry.name}`, "--json", "visibility,licenseInfo"], { encoding: "utf8", timeout: 30_000 })) as { visibility: string; licenseInfo: { key: string } | null }; + if (metadata.visibility === "PUBLIC" && metadata.licenseInfo?.key === "mit") directories.push(join(fleet, entry.name, ".agents/pm")); + } + return directories.sort(); +} + +/** Two meta-generations and two candidates, with every fit covered by the same pre-approved resource Decision. */ +export function liveMetaConfiguration(): MetaConfig { + return { initial_recipe: INITIAL_RECIPE, seed: 42, meta_generations: 2, candidates: 2, timeout_ms: 840_000, + criterion: { confidence: 0.95, minSamples: 10, effectThreshold: 0.01 }, maximum_gap: 0.3, evaluation_samples: 40_000, + adapter: { kind: "process-bandit", allowance: { training_steps: 1, wall_ms: 30_000, storage_bytes: 4096, compute_units: 30_000, tokens: 0 } } }; +} + +/** Build real data at acceptance time and retain results without committing tracker inputs or local paths. */ +export async function runLiveMetaAcceptance(directories: readonly string[], timeoutMs = LIVE_WORKER_DEADLINE_MS): Promise<{ artifacts: string; elapsed_ms: number; report: MetaReport }> { + assert.ok(Number.isInteger(timeoutMs) && timeoutMs > 0 && timeoutMs <= LIVE_WORKER_DEADLINE_MS, "meta_live_timeout"); + const signal = AbortSignal.timeout(timeoutMs); + const started = performance.now(); + const repoRoot = resolve(import.meta.dirname, ".."); + const parent = join(repoRoot, ".agents/pm/runtime/live-meta"); + mkdirSync(parent, { recursive: true }); + const root = mkdtempSync(join(parent, "run-")); + try { + execFileSync("git", ["init", "--quiet", root]); + const dataset = buildTrackerDataset(directories, join(root, "dataset")); + signal.throwIfAborted(); + const initialized = await init("rl", { defaults: true, agentGuidance: "skip", author: "codex-agent" }, { cwd: root, pmRoot: join(root, ".agents/pm") }); + const client = new PmClient({ pmRoot: initialized.path, cwd: root, author: "codex-agent", noExtensions: true }); + const spec = { permitted_promotions: 20, resource_budget: { training_steps: 20, wall_ms: 600_000, storage_bytes: 81_920, compute_units: 600_000, tokens: 0 }, + meta_budget: { training_samples: 20_480, proposal_calls: 4, recipe_promotions: 2 } }; + const approval = await client.create({ id: "approval", type: "Decision", title: "Pre-approved two-generation recipe acceptance", body: `\`\`\`json\n${JSON.stringify(spec)}\n\`\`\`` }); + const config = liveMetaConfiguration(); + writeFileSync(join(root, "programme.json"), JSON.stringify(config, null, 2)); + const report = await runRlMeta(client, { pmRoot: initialized.path, author: "codex-agent" }, { id: "meta-live", config, + dataset: join(root, "dataset"), approval: String(approval.item.id), proposer: "seeded", signal }); + assert.equal(report.generations.length, 2, "meta_live_two_generations"); + assert.equal(report.dataset, dataset.digest); + signal.throwIfAborted(); + const evidence = { artifacts: relative(repoRoot, root), elapsed_ms: performance.now() - started, report }; + writeFileSync(join(root, "summary.json"), JSON.stringify(evidence, null, 2)); + return evidence; + } catch (error) { + writeFileSync(join(root, "failure.json"), JSON.stringify({ failed: true, deadline_aborted: signal.aborted })); + throw error; + } +} + +/** Resolve explicit local fleet input and print the complete acceptance evidence. */ +export async function liveMetaMain(environment: NodeJS.ProcessEnv, emit = printLiveMetaEvidence): Promise { + const started = performance.now(); + const { fleet, timeout } = liveMetaOptions(environment); + const directories = publicTrackerDirectories(fleet); + const evidence = await runLiveMetaAcceptance(directories, Math.floor(timeout - (performance.now() - started))); + emit(evidence); +} + +/** Print one complete evidence envelope without intercepting the test runner's asynchronous protocol stream. */ +export function printLiveMetaEvidence(evidence: Awaited>): void { + process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`); +} + +/** Resolve live-only filesystem input and watchdog budget without opening any source tracker. */ +export function liveMetaOptions(environment: NodeJS.ProcessEnv): { fleet: string; timeout: number } { + return { fleet: environment["PM_RL_TRACKER_ROOT"] ?? resolve(import.meta.dirname, "../../..", "fleet"), + timeout: Number(environment[LIVE_WORKER_TIMEOUT_ENV] ?? LIVE_WORKER_DEADLINE_MS) }; +} + +if (isMainInvocation(process.argv, import.meta.url)) await liveMetaMain(process.env); diff --git a/scripts/live-watchdog.ts b/scripts/live-watchdog.ts index 15656150..57f65ac1 100644 --- a/scripts/live-watchdog.ts +++ b/scripts/live-watchdog.ts @@ -39,11 +39,11 @@ export function liveWatchdogBudget(timeoutMs: number): { graceMs: number; worker /** Launch a bounded worker and stream its transcript; a stalled SDK cannot outlive the parent deadline. */ export async function runLiveCommand(environment: NodeJS.ProcessEnv, emit: (chunk: Buffer) => void, timeoutMs = LIVE_TIMEOUT_MS): Promise { const { graceMs, workerDeadlineMs } = liveWatchdogBudget(timeoutMs); - await streamProcess(process.execPath, [resolve(import.meta.dirname, "live-systemone.ts")], { + await streamProcess(process.execPath, [resolve(import.meta.dirname, environment["PM_RL_LIVE_SUITE"] === "meta" ? "live-meta.ts" : "live-systemone.ts")], { cwd: resolve(import.meta.dirname, ".."), env: { ...environment, [LIVE_WORKER_TIMEOUT_ENV]: String(workerDeadlineMs) }, timeoutMs: timeoutMs - graceMs, escalationMs: graceMs, }, emit); } -if (isMainInvocation(process.argv, import.meta.url)) await runLiveCommand(process.env, (chunk) => { process.stdout.write(chunk); }); +if (isMainInvocation(process.argv, import.meta.url)) await runLiveCommand({ ...process.env, PM_RL_LIVE_SUITE: process.argv[2] }, (chunk) => { process.stdout.write(chunk); }); diff --git a/test/dataset.test.ts b/test/dataset.test.ts new file mode 100644 index 00000000..97ecf498 --- /dev/null +++ b/test/dataset.test.ts @@ -0,0 +1,121 @@ +/** Real Git snapshots prove visibility refusal, prefix isolation, provenance and repository-disjoint splits. */ +import assert from "node:assert/strict"; +import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { test } from "node:test"; +import { buildTrackerDataset, readTrackerDataset, readTrackerSplit, TRACKER_SPLITS, trackerFeature, trackerHistoryExample, type TrackerDataset, type TrackerExample } from "../dataset.ts"; +import { hashJson, type JsonValue } from "../index.ts"; +import { git, withTrackerSources } from "./fixtures/meta-workspace.ts"; + +test("history extraction sees only the pre-terminal prefix, never future states or free text", () => { + const lines = ["open", "in_progress", "closed", "blocked"].map((value) => JSON.stringify({ patch: [{ path: "/metadata/status", value }, { path: "/metadata/description", value: "private fixture text" }] })).join("\n"); + const example = trackerHistoryExample(lines, "public-fixture/pm-alpha", "c".repeat(40), "item")!; + assert.deepEqual(example.prefix, ["open", "in_progress"]); assert.equal(example.label, "completed"); + assert.ok(!JSON.stringify(example).includes("private fixture text")); + assert.equal(trackerHistoryExample('{"patch":[{"path":"/metadata/status","value":"closed"}]}', "repo", "commit", "item"), null); + assert.equal(trackerHistoryExample('{}\n{"patch":[]}', "repo", "commit", "item"), null); + assert.equal(trackerHistoryExample('{"patch":[{"op":"remove","path":"/metadata/status"}]}', "repo", "commit", "item"), null); + assert.throws(() => trackerHistoryExample('{"patch":[{"path":"/metadata/status","value":"unknown"}]}', "repo", "commit", "item"), /unknown_status/); + assert.ok(trackerFeature({ ...example, prefix: ["open", "blocked"] }) < 0); + assert.ok(Math.abs(trackerFeature(example)) <= 0.5); +}); + +test("builder reads committed public MIT histories, records source commits and isolates repositories", async () => { + await withTrackerSources(async ({ root, directories }) => { + writeFileSync(join(directories[0], "history/item-0.jsonl"), "uncommitted garbage"); + writeFileSync(join(directories[0], "history/untracked.jsonl"), "untracked garbage"); + const directory = join(root, "dataset"); const manifest = buildTrackerDataset(directories, directory); + assert.deepEqual(readTrackerDataset(directory), manifest); + const rebuilt = buildTrackerDataset([...directories].reverse(), join(root, "other")); + assert.deepEqual(rebuilt, manifest); + const sets = new Map(TRACKER_SPLITS.map((split) => [split, new Set(readTrackerSplit(directory, manifest, split).map((example) => example.repo))])); + for (const held of ["meta-validation", "final-test"] as const) { + for (const repo of sets.get(held)!) assert.ok(!sets.get("train")!.has(repo) && !sets.get("inner-held-out")!.has(repo)); + } + assert.equal(new Set([...sets.get("meta-validation")!].filter((repo) => sets.get("final-test")!.has(repo))).size, 0); + for (const source of manifest.sources) assert.match(source.commit, /^[a-f0-9]{40}$/); + assert.throws(() => buildTrackerDataset(directories, directory), /EEXIST/); + assert.throws(() => buildTrackerDataset([directories[0], directories[0], directories[1]], join(root, "duplicate")), /duplicate_repo/); + }); +}); + +test("builder fails before reading histories from private, unlicensed, hosted or excluded sources", async () => { + await withTrackerSources(async ({ root, directories }) => { + for (const property of ["RL_FIXTURE_VISIBILITY", "RL_FIXTURE_NO_LICENSE"]) { + process.env[property] = property === "RL_FIXTURE_VISIBILITY" ? "PRIVATE" : "1"; + try { assert.throws(() => buildTrackerDataset(directories, join(root, property)), /public_mit_required/); } + finally { delete process.env[property]; } + } + for (const count of [0, 2, 65]) assert.throws(() => buildTrackerDataset(Array.from({ length: count }, () => directories[0]), join(root, `count-${count}`)), /dataset_bounds/); + for (const seed of [-1, 1.1, 0x100000000]) assert.throws(() => buildTrackerDataset(directories, join(root, "seed"), seed), /dataset_bounds/); + for (const name of ["pm-hosted-data", "pm-web", "pm-gpt"]) { + const path = join(root, name, ".agents/pm"); mkdirSync(path, { recursive: true }); + assert.throws(() => buildTrackerDataset([path, directories[1], directories[2]], join(root, name + "-output")), /forbidden_source/); + } + assert.throws(() => buildTrackerDataset([dirname(directories[0]), directories[1], directories[2]], join(root, "bad-dir")), /tracker_directory/); + const project = dirname(dirname(directories[0])); + git(project, ["remote", "set-url", "origin", "https://example.test/repo"]); + assert.throws(() => buildTrackerDataset(directories, join(root, "foreign")), /github_source/); + for (const repo of ["pm-web", "pm-gpt", "pm-cli"]) { + git(project, ["remote", "set-url", "origin", `git@github.com:public-fixture/${repo}.git`]); + assert.throws(() => buildTrackerDataset(directories, join(root, repo + "-remote")), /excluded_repo/); + } + }); +}); + +test("dataset readers refuse content drift, label leakage and forged repository assignments", async () => { + await withTrackerSources(async ({ root, directories }) => { + const directory = join(root, "dataset"); const manifest = buildTrackerDataset(directories, directory); + const file = join(directory, "train.json"); const original = JSON.parse(readFileSync(file, "utf8")) as TrackerExample[]; + writeFileSync(file, "[]"); assert.throws(() => readTrackerSplit(directory, manifest, "train"), /split_identity/); + for (const examples of [[], [original[0], original[0]], [{ ...original[0], repo: "foreign" }], [{ ...original[0], commit: "wrong" }], + [{ ...original[0], label: "wrong" }], [{ ...original[0], prefix: [] }], [{ ...original[0], prefix: ["closed"] }]]) { + writeFileSync(file, JSON.stringify(examples)); + const modified = { ...manifest, splits: { ...manifest.splits, train: { digest: hashJson(examples as unknown as JsonValue), count: examples.length } } }; + assert.throws(() => readTrackerSplit(directory, modified, "train")); + } + const otherRole = manifest.sources.find((source) => source.role === "final-test")!; + const leaked = [{ ...original[0], repo: otherRole.repo, commit: otherRole.commit }]; + writeFileSync(file, JSON.stringify(leaked)); + assert.throws(() => readTrackerSplit(directory, { ...manifest, splits: { ...manifest.splits, train: { count: 1, digest: hashJson(leaked as unknown as JsonValue) } } }, "train"), /repo_leakage/); + const manifestFile = join(directory, "dataset.json"); + writeFileSync(manifestFile, JSON.stringify({ ...manifest, seed: 100 })); assert.throws(() => readTrackerDataset(directory), /manifest_identity/); + for (const patch of [{ format: "wrong" }, { task: "wrong" }, { sources: [manifest.sources[0], manifest.sources[0]] }]) { + const { digest: _digest, ...record } = { ...manifest, ...patch }; + writeFileSync(manifestFile, JSON.stringify({ ...record, digest: hashJson(record as unknown as JsonValue) })); + assert.throws(() => readTrackerDataset(directory)); + } + const missingLicense = { ...manifest, sources: manifest.sources.map((source) => ({ ...source, license: "bad" })) } as unknown as TrackerDataset; + writeFileSync(file, JSON.stringify(original)); assert.throws(() => readTrackerSplit(directory, missingLicense, "train"), /repo_leakage/); + }); +}); + +test("source limits refuse empty histories and unreachable public commit identities", async () => { + await withTrackerSources(async ({ root, gh, directories }) => { + const project = dirname(dirname(directories[0])); + writeFileSync(gh, `#!${process.execPath}\nconsole.log(process.argv[2]==='api'?'wrong':JSON.stringify({visibility:'PUBLIC',licenseInfo:{key:'mit'},nameWithOwner:process.argv[4]}));\n`); chmodSync(gh, 0o755); + assert.throws(() => buildTrackerDataset(directories, join(root, "unreachable")), /public_commit_required/); + git(project, ["remote", "set-url", "origin", "git@github.com:public-fixture/pm-alpha"]); + }); +}); + +test("empty public histories are recorded as omissions and inadequate prefix diversity refuses a split", async () => { + await withTrackerSources(async ({ root, directories }) => { + /** Commit a new tiny source once; existing append-only histories remain untouched. */ + const source = (name: string, terminal: boolean): string => { + const project = join(root, `pm-${name}`); const directory = join(project, ".agents/pm/history"); mkdirSync(directory, { recursive: true }); + const states = terminal ? ["open", "closed"] : ["open"]; + writeFileSync(join(directory, "item.jsonl"), states.map((value) => JSON.stringify({ patch: [{ path: "/metadata/status", value }] })).join("\n")); + writeFileSync(join(directory, "ignored.txt"), "not a history stream"); + git(project, ["init", "-q"]); git(project, ["remote", "add", "origin", `https://github.com/public-fixture/pm-${name}.git`]); + git(project, ["add", ".agents/pm/history"]); git(project, ["-c", "user.name=Public Fixture", "-c", "user.email=public@example.test", "commit", "-qm", "Synthetic bounded history"]); + return join(project, ".agents/pm"); + }; + const empty = source("empty", false); + const manifest = buildTrackerDataset([...directories, empty], join(root, "with-omission")); + assert.equal(manifest.omitted_sources.length, 1); assert.equal(manifest.omitted_sources[0].repo, "public-fixture/pm-empty"); + assert.throws(() => buildTrackerDataset([empty, directories[0], directories[1]], join(root, "too-few")), /eligible_sources/); + const identical = [source("one", true), source("two", true), source("three", true)]; + assert.throws(() => buildTrackerDataset(identical, join(root, "no-diversity")), /split_size/); + }); +}); diff --git a/test/fixtures/meta-controller.ts b/test/fixtures/meta-controller.ts new file mode 100644 index 00000000..299d158f --- /dev/null +++ b/test/fixtures/meta-controller.ts @@ -0,0 +1,15 @@ +/** Real killable outer controller: pause only after a committed initial fit receipt. */ +import { readFileSync } from "node:fs"; +import { PmClient } from "@unbrained/pm-cli/sdk/core"; +import { runRlMeta } from "../../dist/meta.js"; +import type { MetaRequest } from "../../meta.ts"; +const [pmRoot, file] = process.argv.slice(2); +const request = JSON.parse(readFileSync(file, "utf8")) as MetaRequest; +const client = new PmClient({ pmRoot, author: "meta-test", noExtensions: true }); +const execution: MetaRequest = { ...request, async onStep(key) { + if (key === "initial") { + process.send!({ phase: key }); + await new Promise(() => { setInterval(() => {}, 1000); }); + } +} }; +await runRlMeta(client, { pmRoot, author: "meta-test" }, execution); diff --git a/test/fixtures/meta-workspace.ts b/test/fixtures/meta-workspace.ts new file mode 100644 index 00000000..074b68e4 --- /dev/null +++ b/test/fixtures/meta-workspace.ts @@ -0,0 +1,63 @@ +/** Synthetic histories in real Git snapshots and an ordinary SDK tracker for controller acceptance. */ +import { execFileSync } from "node:child_process"; +import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { after } from "node:test"; +import { PmClient } from "@unbrained/pm-cli/sdk/core"; +import { init } from "@unbrained/pm-cli/sdk/runtime"; +import { buildTrackerDataset } from "../../dataset.ts"; +import { INITIAL_RECIPE, recipeArtifact } from "../../recipe.ts"; +import type { MetaConfig } from "../../meta.ts"; +const roots: string[] = []; +after(() => { for (const root of roots) rmSync(root, { recursive: true, force: true }); }); +export const metaSpec = { permitted_promotions: 100, resource_budget: { training_steps: 100, wall_ms: 3_000_000, storage_bytes: 409_600, compute_units: 3_000_000, tokens: 0 }, + meta_budget: { training_samples: 1_000_000, proposal_calls: 100, recipe_promotions: 100 } }; +export const metaConfig: MetaConfig = { initial_recipe: recipeArtifact({ ...INITIAL_RECIPE.knobs, learning_rate: 1, steps: 1, batch: 128, temperature: 0.5 }), seed: 42, + meta_generations: 2, candidates: 2, timeout_ms: 300_000, criterion: { confidence: 0.95, minSamples: 2, effectThreshold: 0.001 }, maximum_gap: 0.5, + evaluation_samples: 40_000, adapter: { kind: "process-bandit", allowance: { training_steps: 1, wall_ms: 30_000, storage_bytes: 4096, compute_units: 30_000, tokens: 0 } } }; + +/** Run real Git commands against the supplied disposable repository. */ +export function git(root: string, args: string[]): string { return execFileSync("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim(); } + +/** The executable boundary supplies synthetic GitHub metadata; all Git reads use real committed history files. */ +export function trackerSources() { + const root = mkdtempSync(join(tmpdir(), "rl-meta-fixture-")); roots.push(root); + const bin = join(root, "bin"); mkdirSync(bin); + const gh = join(bin, "gh"); + writeFileSync(gh, `#!${process.execPath}\nconst a=process.argv.slice(2); if(a[0]==='api'){ console.log(a[1].split('/').at(-1)); } else { const repo=a[2]; console.log(JSON.stringify({visibility:process.env.RL_FIXTURE_VISIBILITY||'PUBLIC',licenseInfo:process.env.RL_FIXTURE_NO_LICENSE?null:{key:'mit'},nameWithOwner:repo})); }\n`); + chmodSync(gh, 0o755); + const fixture = JSON.parse(readFileSync(new URL("./tracker-histories.json", import.meta.url), "utf8")) as { prefix: string[]; terminal: string }[]; + const directories: string[] = []; + for (const name of ["alpha", "beta", "gamma", "delta", "epsilon"]) { + const project = join(root, `pm-${name}`); const history = join(project, ".agents/pm/history"); mkdirSync(history, { recursive: true }); + git(project, ["init", "-q"]); git(project, ["remote", "add", "origin", `https://github.com/public-fixture/pm-${name}.git`]); + for (let index = 0; index < 32; index += 1) { + const example = fixture[index % fixture.length]; + writeFileSync(join(history, `item-${index}.jsonl`), [...example.prefix, example.terminal].map((status) => JSON.stringify({ patch: [{ path: "/metadata/status", value: status }] })).join("\n")); + } + git(project, ["add", ".agents/pm/history"]); + git(project, ["-c", "user.name=Public Fixture", "-c", "user.email=public@example.test", "commit", "-qm", "Synthetic tracker snapshot"]); + directories.push(join(project, ".agents/pm")); + } + return { root, bin, gh, directories }; +} + +/** Scope a synthetic external metadata executable to a single sequential test process. */ +export async function withTrackerSources(operation: (source: ReturnType) => Promise): Promise { + const source = trackerSources(); const original = process.env.PATH; + process.env.PATH = `${source.bin}:${original}`; + try { return await operation(source); } finally { process.env.PATH = original; } +} + +/** Build the synthetic sealed dataset and initialize a real tracker without consulting injected PM_PATH. */ +export async function metaWorkspace() { + return withTrackerSources(async (source) => { + const dataset = join(source.root, "dataset"); const manifest = buildTrackerDataset(source.directories, dataset); + const project = join(source.root, "controller"); mkdirSync(project); + const { path: pmRoot } = await init("rl", { defaults: true, agentGuidance: "skip", author: "meta-test" }, { cwd: project, pmRoot: join(project, ".agents/pm") }); + const client = new PmClient({ pmRoot, cwd: project, author: "meta-test", noExtensions: true }); + const approval = await client.create({ id: "approval", type: "Decision", title: "Bounded synthetic recipe allowance", body: `\`\`\`json\n${JSON.stringify(metaSpec)}\n\`\`\`` }); + return { ...source, project, dataset, manifest, client, approval: approval.item.id, coordinates: { pmRoot, author: "meta-test" } }; + }); +} diff --git a/test/fixtures/tracker-histories.json b/test/fixtures/tracker-histories.json new file mode 100644 index 00000000..47f07a85 --- /dev/null +++ b/test/fixtures/tracker-histories.json @@ -0,0 +1,6 @@ +[ + {"prefix":["open","in_progress"],"terminal":"closed"}, + {"prefix":["open","blocked"],"terminal":"canceled"}, + {"prefix":["open","in_progress","blocked","in_progress"],"terminal":"closed"}, + {"prefix":["open","in_progress","blocked"],"terminal":"cancelled"} +] diff --git a/test/meta.test.ts b/test/meta.test.ts new file mode 100644 index 00000000..ff3f93cd --- /dev/null +++ b/test/meta.test.ts @@ -0,0 +1,312 @@ +/** Real tracker/process acceptance for recipe search, with corruption, accounting and compartment drills. */ +import assert from "node:assert/strict"; +import { createServer } from "node:http"; +import { once } from "node:events"; +import { fork } from "node:child_process"; +import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { test } from "node:test"; +import { createExtensionTestHarness } from "@unbrained/pm-cli/sdk/testing"; +import extension, { hashJson, withRlController, type JsonValue, type RlCommandResult } from "../index.ts"; +import { compareRecipes, durableRecipeProposals, metaReservation, parseMetaConfig, proposeRecipes, recipeExamples, recipeSuccessor, runRlMeta, scoreTrackerPolicy, type MetaConfig, type MetaRequest } from "../meta.ts"; +import { INITIAL_RECIPE, recipeArtifact, seededRecipes } from "../recipe.ts"; +import { banditCheckpoint } from "../bandit.ts"; +import { readTrackerSplit, type TrackerDataset } from "../dataset.ts"; +import { listProcessJobs } from "../process.ts"; +import { metaConfig, metaSpec, metaWorkspace, withTrackerSources } from "./fixtures/meta-workspace.ts"; +import { liveMetaConfiguration, liveMetaMain, liveMetaOptions, printLiveMetaEvidence, publicTrackerDirectories, runLiveMetaAcceptance } from "../scripts/live-meta.ts"; +import { runLiveCommand } from "../scripts/live-watchdog.ts"; +import { openTrackerEnvironment } from "../tracker-environment.ts"; + +/** Bind a bounded request to the real temporary tracker and synthetic committed sources. */ +function requestFor(workspace: Awaited>, id: string, config = metaConfig): MetaRequest { + return { id, config, dataset: workspace.dataset, approval: workspace.approval, proposer: "seeded" }; +} + +test("meta programme bounds and search domains cannot tune the statistical gate or trainer command", () => { + assert.deepEqual(parseMetaConfig(metaConfig), metaConfig); + for (const key of ["seed", "meta_generations", "candidates", "timeout_ms", "evaluation_samples"] as const) { + for (const value of [NaN, -1, 0x100000001, 1.1]) assert.throws(() => parseMetaConfig({ ...metaConfig, [key]: value })); + } + for (const patch of [{ criterion: { ...metaConfig.criterion, effectThreshold: 0 } }, { maximum_gap: NaN }, { maximum_gap: -1 }, { maximum_gap: 2 }, + { adapter: { kind: "shell" } }, { adapter: { ...metaConfig.adapter, kind: "compose-bandit", image: "sha256:" + "a".repeat(64) } }]) assert.throws(() => parseMetaConfig({ ...metaConfig, ...patch })); + assert.equal(liveMetaConfiguration().meta_generations, 2); + assert.throws(() => parseMetaConfig({ ...metaConfig, criterion: null })); +}); + +test("reward shaping, selection, ordering and temperature affect training only; proxy-only gain is refused", async () => { + const w = await metaWorkspace(); const examples = readTrackerSplit(w.dataset, w.manifest, "train"); + const capabilities = openTrackerEnvironment(w.client, w.coordinates, w.dataset, metaConfig, w.approval); + assert.deepEqual(Object.keys(capabilities).sort(), ["digest", "finalTest", "fit", "selection"]); + const recipe = recipeArtifact({ ...INITIAL_RECIPE.knobs, selection: "balanced", curriculum: "reverse", temperature: 0.5, correct_weight: 0.75, incorrect_weight: 0.1 }); + const training = recipeExamples(examples, recipe, true); const held = recipeExamples(examples, recipe, false); + assert.ok(training.length <= examples.length); assert.ok(training.some((example) => example.rewards[0] === 0.1)); + assert.ok(training.some((example) => example.rewards[1] === 0.1)); assert.deepEqual(new Set(held.flatMap((example) => [...example.rewards])), new Set([0, 1])); + assert.throws(() => recipeExamples(examples.filter((example) => example.label === "completed"), recipe, true), /balanced_class_missing/); + const incumbent = { recipe: INITIAL_RECIPE, weight: 0, checkpoint: banditCheckpoint(0).digest }; + const candidate = { recipe, weight: 1, checkpoint: banditCheckpoint(1).digest }; + const score = scoreTrackerPolicy(examples, candidate, "context", 42); + assert.equal(score.samples, examples.length); + const criterion = { confidence: 0.95, minSamples: 10, effectThreshold: 0.01 }; + const refused = compareRecipes(candidate, incumbent, { mean: 0.5, samples: 1000, context: "context" }, { mean: 0.5, samples: 1000, context: "context" }, criterion); + assert.equal(refused.verdict.decision, "refuse"); assert.ok(refused.gain_lower_bound < 0); + const accepted = compareRecipes(candidate, incumbent, { mean: 0.9, samples: 1000, context: "context" }, { mean: 0.5, samples: 1000, context: "context" }, criterion); + assert.equal(accepted.verdict.decision, "promote"); assert.ok(accepted.gain_lower_bound > 0.01); + const better = compareRecipes({ ...candidate, recipe: recipeArtifact({ ...recipe.knobs, temperature: 1.5 }) }, incumbent, + { mean: 0.95, samples: 1000, context: "context" }, { mean: 0.5, samples: 1000, context: "context" }, criterion); + assert.equal(recipeSuccessor(incumbent, [refused, accepted, better]).promoted, better.candidate.recipe.digest); + assert.deepEqual(recipeSuccessor(incumbent, [refused]), { successor: incumbent, promoted: null }); + assert.equal(compareRecipes(candidate, incumbent, { ...score, context: "different" }, score, criterion).verdict.decision, "refuse"); +}); + +test("two real meta generations retain recipes and process jobs, then resume without double charge or reading inner/final splits", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const request = requestFor(w, "recursive"); const phases: string[] = []; + const first = await runRlMeta(w.client, w.coordinates, { ...request, onStep(key) { phases.push(key); } }); + assert.equal(first.generations.length, 2); assert.ok(first.generations.every((generation) => generation.candidates.length === 2)); + assert.equal(first.generations[1].candidates[0].incumbent, first.generations[0].promoted ?? first.initial.recipe.digest); + assert.ok(phases.indexOf("final-test") > phases.indexOf("m2-promote")); + const jobs = await listProcessJobs(w.client); assert.ok(jobs.length >= 5); + assert.ok(jobs.every((job) => job.settled && job.charge.training_steps === 1 && job.approval === w.approval)); + assert.ok(first.generations.every((generation) => generation.candidates.every((candidate) => !("inner_held_out" in candidate)))); + const reservation = await w.client.get("recursive-reservation"); const original = String(reservation.item.body); + renameSync(join(w.dataset, "inner-held-out.json"), join(w.dataset, "sealed-inner.json")); + renameSync(join(w.dataset, "final-test.json"), join(w.dataset, "sealed-final.json")); + assert.deepEqual(await runRlMeta(w.client, w.coordinates, request), first); + assert.equal(String((await w.client.get("recursive-reservation")).item.body), original); + assert.deepEqual(await listProcessJobs(w.client), jobs); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, config: { ...request.config, seed: 43 } }), /disagrees/); + const receipt = await w.client.get("recursive-step-m1-promote"); const record = JSON.parse(String(receipt.item.body)) as { result: { promoted: string } }; record.result.promoted = "forged"; + await w.client.update(receipt.item.id, { body: JSON.stringify(record) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, request), /damaged/); +}); + +test("cancellation after committed inner work resumes exactly once; a contender cannot launch while the outer lease is held", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const controller = new AbortController(); const request = requestFor(w, "cancel", { ...metaConfig, meta_generations: 1, candidates: 1 }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, signal: controller.signal, async onStep(key) { + if (key === "initial") { + await assert.rejects(runRlMeta(w.client, w.coordinates, request), /controller|contended/); + controller.abort(new Error("synthetic cancellation")); + } + } }), /synthetic cancellation/); + const jobs = await listProcessJobs(w.client); assert.equal(jobs.length, 1); + const report = await runRlMeta(w.client, w.coordinates, request); assert.equal(report.generations.length, 1); + const resumedJobs = await listProcessJobs(w.client); + assert.ok(resumedJobs.length >= 2); assert.deepEqual(resumedJobs.find((job) => job.id === jobs[0].id), jobs[0]); + const cancelled = new AbortController(); cancelled.abort(new Error("pre-cancelled")); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, signal: cancelled.signal }), /pre-cancelled/); +}); + +test("a real outer SIGKILL adopts the committed fit and its original settled reservation", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const request = requestFor(w, "killed", { ...metaConfig, meta_generations: 1, candidates: 1 }); + const file = join(w.root, "kill-request.json"); writeFileSync(file, JSON.stringify(request)); + const environment = { ...process.env }; delete environment.NODE_V8_COVERAGE; + const child = fork(new URL("./fixtures/meta-controller.ts", import.meta.url), [w.coordinates.pmRoot, file], { execArgv: [], env: environment, cwd: w.project, stdio: ["ignore", "ignore", "pipe", "ipc"] }); + let stderr = ""; child.stderr!.on("data", (bytes: Buffer) => { stderr += String(bytes); }); + const exited = once(child, "exit"); + let timer: ReturnType | undefined; + try { + const message = once(child, "message"); + const earlyExit = exited.then(() => { throw new Error(`Outer controller exited early: ${stderr}`); }); + const deadline = new Promise((_resolve, reject) => { timer = setTimeout(() => reject(new Error("Outer checkpoint barrier timed out")), 300_000); }); + await Promise.race([message, earlyExit, deadline]); clearTimeout(timer); + const jobs = await listProcessJobs(w.client); assert.equal(jobs.length, 1); + child.kill("SIGKILL"); await exited; + const report = await runRlMeta(w.client, w.coordinates, request); assert.equal(report.generations.length, 1); + assert.deepEqual((await listProcessJobs(w.client)).find((job) => job.id === jobs[0].id), jobs[0]); + } finally { + clearTimeout(timer); if (child.exitCode === null && child.signalCode === null) { child.kill("SIGKILL"); await exited; } + } +}); + +test("a genuinely better recipe clears the unchanged gate and becomes the next meta generation incumbent", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); + const initial = recipeArtifact({ ...INITIAL_RECIPE.knobs, learning_rate: 0.01, steps: 1, batch: 16, temperature: 2 }); + let seed = 0; + for (; seed < 1000; seed += 1) { + const candidate = seededRecipes(initial, seed, 1, 1)[0].knobs; + if (candidate.steps * candidate.learning_rate * (candidate.correct_weight - candidate.incorrect_weight) / candidate.temperature ** 2 > 4) break; + } + assert.ok(seed < 1000, "synthetic high-signal recipe fixture exists"); + const examples = readTrackerSplit(w.dataset, w.manifest, "meta-validation"); + const expanded = Array.from({ length: 10_000 }, (_, index) => ({ ...examples[index % examples.length], id: hashJson({ index, fixture: true }) })); + writeFileSync(join(w.dataset, "meta-validation.json"), JSON.stringify(expanded)); + const { digest: _digest, ...record } = { ...w.manifest, splits: { ...w.manifest.splits, "meta-validation": { count: expanded.length, digest: hashJson(expanded as unknown as JsonValue) } } }; + const manifest: TrackerDataset = { ...record, digest: hashJson(record as unknown as JsonValue) }; + writeFileSync(join(w.dataset, "dataset.json"), JSON.stringify(manifest)); + const report = await runRlMeta(w.client, w.coordinates, requestFor(w, "improvement", { ...metaConfig, initial_recipe: initial, seed, candidates: 1, evaluation_samples: 100_000 })); + assert.ok(report.generations[0].promoted !== null); + assert.equal(report.generations[1].candidates[0].incumbent, report.generations[0].promoted); + const first = report.generations[0].candidates[0]; assert.equal(first.verdict.decision, "promote"); + assert.ok(first.gain_lower_bound >= metaConfig.criterion.effectThreshold); +}); + +test("an interrupted atomic search reservation is retained once, including drift refusal on resume", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const request = requestFor(w, "transaction", { ...metaConfig, meta_generations: 1, candidates: 1 }); + await assert.rejects(runRlMeta(w.client, { ...w.coordinates, onTransition(context) { if (context.transition === "step_applied") throw new Error("reservation interrupted"); } }, request), /reservation interrupted/); + const item = await w.client.get("transaction-reservation"); const original = JSON.parse(String(item.item.body)) as { charge: Record }; + await w.client.update(item.item.id, { body: JSON.stringify({ ...original, binding: "changed" }) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, request), /meta_reservation_drift/); + for (const patch of [{ format: "foreign" }, { id: "foreign" }, { approval: "foreign" }, { charge: { ...original.charge, proposal_calls: 1 } }]) { + await w.client.update(item.item.id, { body: JSON.stringify({ ...original, ...patch }) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, request), /meta_reservation_drift/); + } + await w.client.create({ id: "copied-reservation", type: "Decision", title: "Copied control receipt", body: JSON.stringify(original) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, id: "copied" }), /meta_reservation_drift/); + await w.client.update(item.item.id, { body: JSON.stringify(original) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, onStep(key) { if (key === "programme") throw new Error("retained once"); } }), /retained once/); + assert.equal(String((await w.client.get(item.item.id)).item.body), JSON.stringify(original)); + const task = await w.client.create({ type: "Task", title: "Not an approval", body: '```json\n{}\n```' }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, approval: task.item.id }), /meta_approval_required/); +}); + +test("two distinct outer programmes cannot oversubscribe one approved search reservation", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); + const spec = { ...metaSpec, meta_budget: { training_samples: 1024, proposal_calls: 0, recipe_promotions: 1 } }; + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify(spec)}\n\`\`\`` }); + const config = { ...metaConfig, meta_generations: 1, candidates: 1 }; + const outcomes = await Promise.allSettled(["concurrent-one", "concurrent-two"].map((id) => runRlMeta(w.client, w.coordinates, { + ...requestFor(w, id, config), onStep(key) { if (key === "programme") throw new Error("stop after the sole reservation"); }, + }))); + assert.ok(outcomes.every((outcome) => outcome.status === "rejected")); + const reasons = outcomes.map((outcome) => String((outcome as PromiseRejectedResult).reason)); + assert.equal(reasons.filter((reason) => reason.includes("meta_budget_exhausted")).length, 1, reasons.join("\n")); + assert.equal(reasons.filter((reason) => reason.includes("sole reservation")).length, 1, reasons.join("\n")); +}); + +test("one pre-approved Decision cannot be enlarged, replaced or oversubscribed, including pretty reservation bodies", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); + await w.client.create({ type: "Task", title: "Unrelated data record", body: "Synthetic evaluator content must stay outside accounting reads." }); + for (const key of ["training_samples", "proposal_calls", "recipe_promotions"] as const) { + const spec = { ...metaSpec, meta_budget: { ...metaSpec.meta_budget, [key]: 0 } }; + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify(spec)}\n\`\`\`` }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, `exhaust-${key.replaceAll("_", "-")}`), proposer: "decision-model" }), new RegExp(`meta_budget_exhausted: ${key}`)); + } + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify(metaSpec)}\n\`\`\`` }); + const request = requestFor(w, "bound", { ...metaConfig, meta_generations: 1, candidates: 1 }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, async onStep(key) { + if (key === "programme") await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: 101 })}\n\`\`\`` }); + } }), /meta_budget_drift/); + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify(metaSpec)}\n\`\`\`` }); + const reservation = await w.client.get("bound-reservation"); + const replacement = await w.client.create({ type: "Decision", title: "Identical spec with a different approval identity", body: `\`\`\`json\n${JSON.stringify(metaSpec)}\n\`\`\`` }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, approval: replacement.item.id, onStep(key) { if (key === "programme") throw new Error("approval identity switched"); } }), /disagrees/); + await w.client.update(reservation.item.id, { title: "Renamed reserved search", body: JSON.stringify(JSON.parse(String(reservation.item.body)), null, 2) }); + await w.client.create({ id: "foreign-reservation", type: "Decision", title: "Unbound copied envelope", body: reservation.item.body }); + await w.client.create({ id: "prose-reservation", type: "Decision", title: "Unrelated control record", body: "Prose mentioning pm-rl/meta-reservation/1" }); + const independent = await w.client.create({ id: "independent-reservation", type: "Decision", title: "Different approval allocation" }); + const copied = JSON.parse(String(reservation.item.body)) as Record; + await w.client.update(independent.item.id, { body: JSON.stringify({ ...copied, id: independent.item.id, approval: replacement.item.id }) }); + for (const [index, value] of [-1, 0.5, Number.MAX_SAFE_INTEGER + 1].entries()) { + const record = JSON.parse(String(reservation.item.body)) as { charge: Record }; + record.charge.training_samples = value; + await w.client.update(reservation.item.id, { body: JSON.stringify(record) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, `invalid-charge-${index}`, { ...metaConfig, meta_generations: 1, candidates: 1 })), /meta_reservation_charge/); + } + await w.client.update(reservation.item.id, { body: String(reservation.item.body) }); + const spec = { ...metaSpec, meta_budget: { ...metaSpec.meta_budget, training_samples: 1024 } }; + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify(spec)}\n\`\`\`` }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, "second", { ...metaConfig, meta_generations: 1, candidates: 1 }), + onStep(key) { if (key === "programme") throw new Error("hidden reservation admitted"); }, + }), /training_samples/); + for (const body of ["plain", "pm-rl/meta-reservation/1 prose", '{"other":"pm-rl/meta-reservation/1"}']) assert.equal(metaReservation(body), null); + assert.ok(metaReservation(String((await w.client.get("bound-reservation")).item.body)) !== null); + for (const body of ["no fence", '```json\n{}\n```', '```json\n{"meta_budget":null}\n```', '```json\n{"meta_budget":{"training_samples":-1}}\n```']) { + await w.client.update(w.approval, { body }); await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "invalid-approval"))); + } + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, "invalid-proposer"), proposer: "bad" as "seeded" }), /meta_proposer/); +}); + +test("decision-model proposals send only recipes through the calibrated adapter and fall back on unavailable local models", async () => { + let mode = "available"; const states: string[] = []; let rankedFirst = ""; + const server = createServer(async (request, response) => { + response.setHeader("content-type", "application/json"); + if (request.url === "/api/tags") { + if (mode === "http-error") response.statusCode = 503; + response.end(JSON.stringify({ models: mode === "missing" ? [] : [{ name: "tev1:4b", ...(mode === "remote" ? { remote_host: "external" } : {}), ...(mode === "remote-model" ? { remote_model: "external" } : {}) }] })); return; + } + let body = ""; for await (const chunk of request) body += String(chunk); + const parsed = JSON.parse(body) as { state: string; questions: { recipe: { criteria: Record } } }; states.push(parsed.state); + const options = Object.keys(parsed.questions.recipe.criteria); + rankedFirst = options.at(-1)!; + response.end(JSON.stringify(mode === "corrupt" ? {} : { answers: { recipe: { probabilities: Object.fromEntries(options.map((option) => [option, mode === "ranked" ? (option === rankedFirst ? 0.7 : 0.1) : 1 / options.length])) } }, usage: { input_tokens: 1, output_tokens: 1 } })); + }); + server.listen(0, "127.0.0.1"); await once(server, "listening"); + const address = server.address(); assert.ok(address !== null && typeof address === "object"); + const request = { config: metaConfig, proposer: "decision-model" as const, decisionEndpoint: `http://127.0.0.1:${address.port}` }; + try { + const proposals = await proposeRecipes(request, INITIAL_RECIPE, 1, new AbortController().signal); + assert.equal(proposals.proposer, "decision-model"); assert.equal(proposals.recipes.length, metaConfig.candidates); + mode = "ranked"; + const ranked = await proposeRecipes(request, INITIAL_RECIPE, 1, new AbortController().signal); + assert.equal(ranked.recipes[0].digest, rankedFirst); mode = "available"; + assert.ok(states.every((state) => !state.includes("prefix") && !state.includes("label") && !state.includes("held_out"))); + const workspace = await metaWorkspace(); + await workspace.client.create({ type: "Task", title: "Unrelated evaluator item", body: "Synthetic held-out canary" }); + const first = await durableRecipeProposals(workspace.client, "proposer", request, INITIAL_RECIPE, 1, new AbortController().signal); + const calls = states.length; + assert.deepEqual(await durableRecipeProposals(workspace.client, "proposer", request, INITIAL_RECIPE, 1, new AbortController().signal), first); + assert.equal(states.length, calls); + const item = await workspace.client.get("proposer-m1-proposal-attempt"); const record = JSON.parse(String(item.item.body)) as Record; + await workspace.client.update(item.item.id, { body: JSON.stringify({ ...record, state: "intent" }) }); + assert.equal((await durableRecipeProposals(workspace.client, "proposer", request, INITIAL_RECIPE, 1, new AbortController().signal)).proposer, "seeded:unresolved-model-attempt"); + assert.equal(states.length, calls); + await workspace.client.update(item.item.id, { body: JSON.stringify({ ...record, state: "invalid" }) }); + await assert.rejects(durableRecipeProposals(workspace.client, "proposer", request, INITIAL_RECIPE, 1, new AbortController().signal), /proposal_state/); + await workspace.client.update(item.item.id, { body: JSON.stringify({ ...record, digest: "corrupt" }) }); + await assert.rejects(durableRecipeProposals(workspace.client, "proposer", request, INITIAL_RECIPE, 1, new AbortController().signal), /proposal_receipt/); + await assert.rejects(durableRecipeProposals(workspace.client, "proposer", { ...request, config: { ...metaConfig, seed: 1 } }, INITIAL_RECIPE, 1, new AbortController().signal), /proposal_drift/); + for (mode of ["missing", "remote", "remote-model", "corrupt", "http-error"]) { + assert.deepEqual((await proposeRecipes(request, INITIAL_RECIPE, 1, new AbortController().signal)).recipes, seededRecipes(INITIAL_RECIPE, metaConfig.seed, 1, metaConfig.candidates)); + } + const controller = new AbortController(); controller.abort(new Error("proposal cancelled")); + await assert.rejects(proposeRecipes(request, INITIAL_RECIPE, 1, controller.signal), /proposal cancelled/); + await assert.rejects(proposeRecipes({ config: metaConfig, proposer: "decision-model" }, INITIAL_RECIPE, 1, controller.signal), /proposal cancelled/); + await assert.rejects(durableRecipeProposals(workspace.client, "default-endpoint", { config: metaConfig, proposer: "decision-model" }, INITIAL_RECIPE, 1, controller.signal), /proposal cancelled/); + await assert.rejects(proposeRecipes({ ...request, decisionEndpoint: "https://example.test" }, INITIAL_RECIPE, 1, new AbortController().signal), /local_proposer_required/); + } finally { server.closeAllConnections(); await new Promise((done) => { server.close(() => done()); }); } + assert.equal((await proposeRecipes({ config: metaConfig, proposer: "decision-model", decisionEndpoint: "http://127.0.0.1:1" }, INITIAL_RECIPE, 1, new AbortController().signal)).proposer, "seeded:model-unavailable"); +}); + +test("live entry point builds only synthetic public snapshots in ordinary acceptance tests and retains failure evidence", { timeout: 600_000 }, async () => { + assert.ok(liveMetaOptions({}).fleet.endsWith("fleet")); + assert.equal(liveMetaOptions({ PM_RL_TRACKER_ROOT: "synthetic", PM_LIVE_WORKER_TIMEOUT_MS: "1000" }).timeout, 1000); + await assert.rejects(runLiveMetaAcceptance([], 1000), /dataset_bounds/); + await withTrackerSources(async (source) => { + let result: Awaited> | undefined; + await liveMetaMain({ PM_RL_TRACKER_ROOT: source.root }, (evidence) => { result = evidence; }); + assert.equal(result!.report.generations.length, 2); + const original = process.stdout.write; let printed = ""; + process.stdout.write = ((chunk: string | Uint8Array): boolean => { printed += String(chunk); return true; }) as typeof process.stdout.write; + try { printLiveMetaEvidence(result!); } finally { process.stdout.write = original; } + assert.deepEqual(JSON.parse(printed), result); + }); +}); + +test("public command builds a dataset and executes real bounded meta work, retaining errors for malformed configuration", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const harness = await createExtensionTestHarness(extension, { name: "pm-rl", capabilities: ["commands", "hooks", "schema"] }); + await withTrackerSources(async (source) => { + const built = await harness.runCommand({ command: "rl dataset build", pmRoot: w.coordinates.pmRoot, args: source.directories.slice(1), + options: { fromTrackers: source.directories[0], output: join(source.root, "command-dataset") } }); + assert.equal((built.result as RlCommandResult).action, "rl-dataset-build"); + const invalid = await harness.runCommand({ command: "rl dataset build", pmRoot: w.coordinates.pmRoot, args: [], options: { fromTrackers: source.directories[0], output: join(source.root, "invalid-dataset"), seed: "1" } }); + assert.equal(invalid.handled, false); assert.match(invalid.errorMessage!, /dataset_bounds/); + assert.equal(publicTrackerDirectories(source.root).length, 5); + writeFileSync(join(source.root, "regular-file"), "ignored"); + for (const name of ["pm-web", "pm-gpt", "pm-cli"]) mkdirSync(join(source.root, name)); + assert.equal(publicTrackerDirectories(source.root).length, 5); + process.env.RL_FIXTURE_VISIBILITY = "PRIVATE"; + try { assert.equal(publicTrackerDirectories(source.root).length, 0); } finally { delete process.env.RL_FIXTURE_VISIBILITY; } + process.env.RL_FIXTURE_NO_LICENSE = "1"; + try { assert.equal(publicTrackerDirectories(source.root).length, 0); } finally { delete process.env.RL_FIXTURE_NO_LICENSE; } + }); + const file = join(w.root, "meta.json"); writeFileSync(file, JSON.stringify({ ...metaConfig, meta_generations: 1, candidates: 1 })); + const run = await harness.runCommand({ command: "rl meta run", pmRoot: w.coordinates.pmRoot, args: ["command"], options: { file, dataset: w.dataset, approval: w.approval } }); + assert.equal((run.result as RlCommandResult).action, "rl-meta-run"); + const badProposer = await harness.runCommand({ command: "rl meta run", pmRoot: w.coordinates.pmRoot, args: ["bad-proposer"], options: { file, dataset: w.dataset, approval: w.approval, proposer: "invalid" } }); + assert.equal(badProposer.handled, false); assert.match(badProposer.errorMessage!, /meta_proposer/); + writeFileSync(file, "{}"); + const badConfiguration = await harness.runCommand({ command: "rl meta run", pmRoot: w.coordinates.pmRoot, args: ["bad-command"], options: { file, dataset: w.dataset, approval: w.approval, proposer: "seeded" } }); + assert.equal(badConfiguration.handled, false); + await assert.rejects(runLiveMetaAcceptance(w.directories, 0), /meta_live_timeout/); + await assert.rejects(runLiveCommand({ ...process.env, PM_RL_LIVE_SUITE: "meta", PM_RL_TRACKER_ROOT: join(w.root, "missing") }, () => {}, 60_000), /ENOENT/); +}); diff --git a/test/recipe.test.ts b/test/recipe.test.ts new file mode 100644 index 00000000..328c0c48 --- /dev/null +++ b/test/recipe.test.ts @@ -0,0 +1,49 @@ +/** Recipe domains, identities, deterministic search and inner lineage are behavioural contracts. */ +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { INITIAL_RECIPE, RECIPE_BOUNDS, parseRecipe, recipeArtifact, seededRecipes } from "../recipe.ts"; +import { parseLoopConfig, generationTrainingConfig, seedTrainingConfig, runLoopGeneration, parseStoredLoopGeneration, verifyStoredLoopGeneration } from "../loop.ts"; +import { banditCheckpoint } from "../bandit.ts"; +import { configuration } from "./fixtures/process-workspace.ts"; +import type { JsonValue } from "../index.ts"; + +test("recipes bind every declared knob and refuse malformed domains or identities", () => { + assert.deepEqual(parseRecipe(INITIAL_RECIPE), INITIAL_RECIPE); + assert.match(INITIAL_RECIPE.digest, /^sha256:[a-f0-9]{64}$/); + assert.throws(() => parseRecipe(null), /recipe_record/); + assert.throws(() => parseRecipe({ ...INITIAL_RECIPE, format: "2" }), /recipe_identity/); + assert.throws(() => parseRecipe({ ...INITIAL_RECIPE, bounds: {} }), /recipe_identity/); + assert.throws(() => parseRecipe({ ...INITIAL_RECIPE, unknown: true }), /recipe_identity/); + assert.throws(() => recipeArtifact({ ...INITIAL_RECIPE.knobs, unknown: true } as typeof INITIAL_RECIPE.knobs), /recipe_knobs/); + for (const key of ["learning_rate", "steps", "batch", "temperature", "correct_weight", "incorrect_weight"] as const) { + for (const value of [NaN, RECIPE_BOUNDS[key][0] - 1, RECIPE_BOUNDS[key][1] + 1]) assert.throws(() => recipeArtifact({ ...INITIAL_RECIPE.knobs, [key]: value }), /recipe_bound/); + } + assert.throws(() => recipeArtifact({ ...INITIAL_RECIPE.knobs, steps: 1.1 }), /recipe_integer/); + assert.throws(() => recipeArtifact({ ...INITIAL_RECIPE.knobs, batch: 16.1 }), /recipe_integer/); + assert.throws(() => recipeArtifact({ ...INITIAL_RECIPE.knobs, selection: "bad" as "all" }), /recipe_category/); + assert.throws(() => recipeArtifact({ ...INITIAL_RECIPE.knobs, curriculum: "bad" as "forward" }), /recipe_category/); +}); + +test("seeded proposals replay exactly, stay bounded and vary all training decisions", () => { + const first = seededRecipes(INITIAL_RECIPE, 42, 1, 8); + assert.deepEqual(first, seededRecipes(INITIAL_RECIPE, 42, 1, 8)); + assert.notDeepEqual(first, seededRecipes(INITIAL_RECIPE, 42, 2, 8)); + for (const recipe of first) assert.deepEqual(parseRecipe(recipe), recipe); + assert.equal(new Set(first.map((recipe) => recipe.knobs.selection)).size, 2); + assert.equal(new Set(first.map((recipe) => recipe.knobs.curriculum)).size, 2); + for (const count of [0, 9, 1.1]) assert.throws(() => seededRecipes(INITIAL_RECIPE, 42, 1, count)); +}); + +test("each inner programme and generation names its actual recipe, and resume refuses recipe drift", () => { + const recipe = recipeArtifact({ ...INITIAL_RECIPE.knobs, steps: 2, batch: 128, learning_rate: 0.5 }); + const raw = { ...configuration, learning_rate: 0.5, recipe: recipe as unknown as JsonValue }; + const config = parseLoopConfig(raw); + const receipt = runLoopGeneration(config, { learningRate: 0.5, evaluationSamples: config.evaluationSamples }, 1, banditCheckpoint(0)); + const serialized = generationTrainingConfig(config, { learningRate: 0.5, evaluationSamples: config.evaluationSamples }, 1, receipt); + const stored = parseStoredLoopGeneration(serialized, "recipe fixture"); + assert.equal(stored.recipeDigest, recipe.digest); + assert.equal((seedTrainingConfig(config) as Record).recipe, recipe.digest); + assert.deepEqual(verifyStoredLoopGeneration(config, { learningRate: 0.5, evaluationSamples: config.evaluationSamples }, 1, banditCheckpoint(0), stored), receipt); + assert.throws(() => verifyStoredLoopGeneration(config, { learningRate: 0.5, evaluationSamples: config.evaluationSamples }, 1, banditCheckpoint(0), { ...stored, recipeDigest: INITIAL_RECIPE.digest }), /recipe/); + for (const override of [{ learning_rate: 0.6 }, { max_generations: 3 }, { samples_per_generation: 64 }]) assert.throws(() => parseLoopConfig({ ...raw, ...override }), /Recipe knobs/); +}); diff --git a/tracker-environment.ts b/tracker-environment.ts new file mode 100644 index 00000000..8e2c29a4 --- /dev/null +++ b/tracker-environment.ts @@ -0,0 +1,98 @@ +/** Sealed tracker evaluator capabilities: search receives scores and policies, never inner or final examples. */ +import assert from "node:assert/strict"; +import type { PmClient } from "@unbrained/pm-cli/sdk/core"; +import { banditCheckpoint, type BanditExample } from "./bandit.ts"; +import { hashJson, readCompleteLoopItem, runRlLoop, type JsonValue } from "./index.ts"; +import { readTrackerDataset, readTrackerSplit, trackerFeature, type TrackerDataset, type TrackerExample } from "./dataset.ts"; +import { parseStoredLoopGeneration } from "./loop.ts"; +import { parseGenerationSpec } from "./lineage.ts"; +import type { ProcessCoordinates } from "./process.ts"; +import type { Recipe } from "./recipe.ts"; +import type { MetaConfig, MetaRequest, MetaReport, RecipePolicy, TrackerScore } from "./meta.ts"; + +/** The outer search has no dataset coordinate or example-reading method. */ +export interface TrackerEnvironment { + readonly digest: string; + fit(recipe: Recipe, id: string, signal: AbortSignal): Promise; + selection(candidate: RecipePolicy, incumbent: RecipePolicy): { score: TrackerScore; baseline: TrackerScore }; + finalTest(initial: RecipePolicy, incumbent: RecipePolicy): MetaReport["final_test"]; +} + +/** Open evaluator capabilities without loading either held-out compartment; final testing stays lazy until selection ends. */ +export function openTrackerEnvironment(client: PmClient, coordinates: ProcessCoordinates, directory: string, config: MetaConfig, approval: string): TrackerEnvironment { + const manifest = readTrackerDataset(directory); + return { + digest: manifest.digest, + fit: async (recipe, id, signal) => fitRecipe(client, coordinates, { config, dataset: directory, approval }, manifest, recipe, id, signal), + selection(candidate, incumbent) { + const examples = readTrackerSplit(directory, manifest, "meta-validation"); + const context = manifest.splits["meta-validation"].digest; + return { score: scoreTrackerPolicy(examples, candidate, context, config.seed), baseline: scoreTrackerPolicy(examples, incumbent, context, config.seed) }; + }, + finalTest(initial, incumbent) { + const examples = readTrackerSplit(directory, manifest, "final-test"); + const context = manifest.splits["final-test"].digest; + return { before: scoreTrackerPolicy(examples, initial, context, config.seed), after: scoreTrackerPolicy(examples, incumbent, context, config.seed) }; + }, + }; +} + +/** Convert training-only prefixes to a binary exact-match environment, applying only declared recipe knobs. */ +export function recipeExamples(examples: readonly TrackerExample[], recipe: Recipe, training: boolean): BanditExample[] { + let selected = [...examples]; + if (training && recipe.knobs.selection === "balanced") { + const completed = selected.filter((example) => example.label === "completed"); + const cancelled = selected.filter((example) => example.label === "cancelled"); + const limit = Math.min(completed.length, cancelled.length); + assert.ok(limit > 0, "meta_balanced_class_missing"); + selected = [...completed.slice(0, limit), ...cancelled.slice(0, limit)]; + } + if (training && recipe.knobs.curriculum === "reverse") selected.reverse(); + return selected.map((example) => { + const correct = training ? recipe.knobs.correct_weight : 1; + const incorrect = training ? recipe.knobs.incorrect_weight : 0; + return { id: example.id, feature: trackerFeature(example) / recipe.knobs.temperature, + rewards: example.label === "completed" ? [incorrect, correct] : [correct, incorrect] }; + }); +} + +/** Sample one action per unique prefix on a stream shared across policies, rewarding only exact class matches. */ +export function scoreTrackerPolicy(examples: readonly TrackerExample[], policy: RecipePolicy, context: string, seed: number): TrackerScore { + let correct = 0; + for (const example of examples) { + const draw = Number.parseInt(hashJson({ seed, id: example.id }).slice(7, 15), 16) / 0x100000000; + const probability = 1 / (1 + Math.exp(-policy.weight * trackerFeature(example) / policy.recipe.knobs.temperature)); + const prediction = draw < probability ? "completed" : "cancelled"; + if (prediction === example.label) correct += 1; + } + return { mean: correct / examples.length, samples: examples.length, context }; +} + +/** Run the inner loop behind a compartment boundary; its held-out examples and scores never return to search. */ +async function fitRecipe(client: PmClient, coordinates: ProcessCoordinates, request: Pick, manifest: TrackerDataset, recipe: Recipe, id: string, signal: AbortSignal): Promise { + const training = recipeExamples(readTrackerSplit(request.dataset, manifest, "train"), recipe, true); + const evaluation = recipeExamples(readTrackerSplit(request.dataset, manifest, "inner-held-out"), recipe, false); + assert.ok(!training.some((example) => new Set(evaluation.map((held) => held.id)).has(example.id)), "meta_inner_overlap"); + const config = request.config; + const report = await runRlLoop(client, coordinates, { id, approval: request.approval, signal, config: { + recipe: recipe as unknown as JsonValue, environment: { name: "Public tracker terminal disposition", version: manifest.digest }, + training: training as unknown as JsonValue, evaluation: evaluation as unknown as JsonValue, initial_weight: 0, + seed: config.seed, max_generations: recipe.knobs.steps, samples_per_generation: recipe.knobs.batch, + budget: recipe.knobs.steps * recipe.knobs.batch, learning_rate: recipe.knobs.learning_rate, + minimum_improvement: config.criterion.effectThreshold, maximum_gap: config.maximum_gap, + evaluation_samples: config.evaluation_samples, confidence: config.criterion.confidence, min_samples: config.criterion.minSamples, + adapter: config.adapter as unknown as JsonValue, + } }); + assert.ok(!["process_failed", "process_cancelled", "process_invalidated", "wall_limit_exceeded", "checkpoint_limit_exceeded"].includes(report.stop_reason), "meta_inner_failed"); + let weight = 0; + const accepted = report.generations.filter((generation) => generation.promoted).at(-1); + if (accepted !== undefined) { + const item = await readCompleteLoopItem(client, accepted.item); + const fence = /```json\n([\s\S]+?)\n```/.exec(String(item.item.body)); + assert.ok(fence !== null, "meta_checkpoint_receipt"); + weight = parseStoredLoopGeneration(parseGenerationSpec(fence[1], "Inner generation").training_config as JsonValue, "Inner generation").candidateWeight; + } + assert.equal(banditCheckpoint(weight).digest, report.final_checkpoint, "meta_checkpoint_identity"); + return { recipe, weight, checkpoint: report.final_checkpoint }; +} + From f622177dc0538de79d76a24655593babae39fe63 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 07:36:25 +0200 Subject: [PATCH 02/24] ci: run exact npm and Bun release gates with isolated identity --- .agents/pm/features/pm-rl-meta.toon | 11 ++++-- .agents/pm/history/pm-rl-meta.jsonl | 5 +++ .github/workflows/ci.yml | 57 +++++++++++++---------------- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 2a6a5b36..109623bb 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T04:49:36.187Z" +updated_at: "2026-10-18T05:36:06.534Z" assignee: codex-agent claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[9]{created_at,author,text}: +comments[13]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -22,7 +22,12 @@ comments[9]{created_at,author,text}: "2026-10-18T03:58:51.495Z",codex-agent,"Final real-data acceptance after evaluator capability isolation passes again: the complete dataset manifest and policy/gate/final-test report are byte-equivalent as JSON to the first successful run (same 25 eligible public repos, 1767 examples, four refused recipes, gain 0 with lower bound -0.21778781183411927, final-test 198/385 before and after). No statistical or feature tuning followed final-test exposure. The governing programme now binds the canonical approval item identity as well as its spec digest; an identical replacement Decision cannot switch budgets during resume. Full npm and Bun release gates follow with unchanged thresholds and CI identity isolation." "2026-10-18T04:05:27.268Z",codex-agent,"Self-review tightened the evaluator boundary before the final gates: outer accounting and proposal recovery now perform certified Decision metadata listings with bodies excluded, then open only the stable reservation namespace or exact proposal-attempt record. They no longer request every tracker body, which could include inner environment/seed datasets. Reservation discovery uses stable item identities, so a title edit cannot hide an allocation. Regression cases include unrelated prose, copied envelopes, independent approvals and replacement Decisions with identical specs. The first release-gate attempt was deliberately interrupted for this correction; no passing full-gate result is claimed from it." "2026-10-18T04:49:36.187Z",codex-agent,"Final ledger regressions pass 3/3: interrupted atomic reservations retain one charge, independent programmes cannot oversubscribe, and approval replacement or copied/corrupt reservation tuples are refused. Programme identity, canonical approval ID, recipe plan and exact charge vector are bound into the durable receipt. Full npm and Bun release gates now run against the frozen implementation; thresholds and legacy deadlines remain unchanged." -files[18]{path,scope}: + "2026-10-18T05:09:33.934Z",codex-agent,"Full npm gate attempt on 1b00e1b reached an existing regression timeout: SIGKILL at every HTTP-to-PM receipt boundary replays one decision per query exceeded its unchanged 300000 ms limit (300019.19627 ms). Its merged fix and prior measured evidence remain documented under pm-rl-bi4v. The new dataset cases passed 6/6 before this failure. Retain this failed attempt, inspect the completed result, and retry without extending deadlines or changing coverage thresholds; no passing full-gate claim is made." + "2026-10-18T05:29:44.668Z",codex-agent,"Draft PR #84 is open at 1b00e1b67c3fe7b6b396d28ecf6d8793843b3840. GitHub Node 26 CI passes 611/611, zero failures/skips, all 35 authored sources at statements/lines/branches/functions 100/100/100/100. The original eight-boundary HTTP SIGKILL drill passes there in 15884.547137 ms under its unchanged 300000 ms deadline. CodeQL passed; Node 22 remains running. Local npm remains a failed attempt because of the earlier timeout and is continuing for diagnostic coverage; local npm and Bun gates are still required. CodeRabbit explicitly skipped review of the draft, which is not approval evidence." + "2026-10-18T05:34:31.818Z",codex-agent,"Both original CI matrix jobs passed on 1b00e1b: Node 22 and 26 each 611/611, zero failures/skips, 35 sources at 100/100/100/100 and 295 documented declarations. To execute the exact required npm and Bun release commands reproducibly, CI now retains test (22) and test (26), adds Bun release (26), and invokes the full existing release:check script with isolated HOME and global/system Git configuration. No gate, deadline, source scope, threshold, dependency pin or release approval changed. The overloaded-host npm attempt was deliberately stopped after its recorded HTTP crash-drill timeout; its cancellation output is retained and is not passing evidence. Exact-command CI receipts remain pending." + "2026-10-18T05:36:06.534Z",codex-agent,"The strengthened CI uses separate literal npm and Bun steps selected by the fixed matrix. The static publish-attestation gate correctly refused an unresolved dynamic executable during development; the literal version passes the verifier and all 8/8 attestation tests, zero skips. YAML parsing confirms exactly three intended combinations. Required Node check names, the Bun install check and read-only workflow permissions are preserved. Exact release-command CI now runs on the branch; release approval remains disabled." +files[19]{path,scope}: + .github/workflows/ci.yml,project dataset.ts,project examples/meta-approval.md,project examples/meta-trackers.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 346446e7..44f7d926 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -21,3 +21,8 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T04:40:58.354Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/15/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/14/path","value":"test/fixtures/tracker-histories.json"},{"op":"replace","path":"/metadata/files/13/path","value":"test/fixtures/meta-workspace.ts"},{"op":"replace","path":"/metadata/files/12/path","value":"test/fixtures/meta-controller.ts"},{"op":"replace","path":"/metadata/files/11/path","value":"test/dataset.test.ts"},{"op":"replace","path":"/metadata/files/10/path","value":"scripts/live-watchdog.ts"},{"op":"replace","path":"/metadata/files/9/path","value":"scripts/live-meta.ts"},{"op":"replace","path":"/metadata/files/8/path","value":"recipe.ts"},{"op":"replace","path":"/metadata/files/7/path","value":"package.json"},{"op":"replace","path":"/metadata/files/6/path","value":"meta.ts"},{"op":"replace","path":"/metadata/files/5/path","value":"manifest.json"},{"op":"replace","path":"/metadata/files/4/path","value":"loop.ts"},{"op":"replace","path":"/metadata/files/3/path","value":"index.ts"},{"op":"replace","path":"/metadata/files/2/path","value":"examples/meta-trackers.json"},{"op":"replace","path":"/metadata/files/1/path","value":"examples/meta-approval.md"},{"op":"add","path":"/metadata/files/16","value":{"path":"test/recipe.test.ts","scope":"project"}},{"op":"add","path":"/metadata/files/17","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T04:40:58.354Z"}],"before_hash":"da11ba831e2626ba2eb65d462f2b3ff40f209acc0eeb85f2ba2cf85cf5822e60","after_hash":"bccf935e16a8f7cfbd07040c4e4607fbd002a00f7f8d29473838f7d26391cac9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"f78c0144f99ebbc55be09b028643aefe99580f97169356ffa803103ec9fb350a"} {"hash_algorithm":"sha256","ts":"2026-10-18T04:41:07.624Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/3/path","value":"examples/meta-approval.md"},{"op":"replace","path":"/metadata/docs/2/path","value":"docs/meta-recursive.md"},{"op":"replace","path":"/metadata/docs/1/path","value":"docs/meta-live-evidence.json"},{"op":"replace","path":"/metadata/docs/0/path","value":"docs/durable-systemone-validation.md"},{"op":"add","path":"/metadata/docs/4","value":{"path":"README.md","scope":"project"}},{"op":"add","path":"/metadata/docs/5","value":{"path":"RECURSIVE_TRAINING.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T04:41:07.624Z"}],"before_hash":"bccf935e16a8f7cfbd07040c4e4607fbd002a00f7f8d29473838f7d26391cac9","after_hash":"d24b0d8148aea90d83ba305c15b2f95077fbdc961840e28532927a80659d4be4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fbc56f47c84ce26598848228d4e3cee0f540757af34cae4dfea0528e37f8882a"} {"hash_algorithm":"sha256","ts":"2026-10-18T04:49:36.187Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-10-18T04:49:36.187Z","author":"codex-agent","text":"Final ledger regressions pass 3/3: interrupted atomic reservations retain one charge, independent programmes cannot oversubscribe, and approval replacement or copied/corrupt reservation tuples are refused. Programme identity, canonical approval ID, recipe plan and exact charge vector are bound into the durable receipt. Full npm and Bun release gates now run against the frozen implementation; thresholds and legacy deadlines remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T04:49:36.187Z"}],"before_hash":"d24b0d8148aea90d83ba305c15b2f95077fbdc961840e28532927a80659d4be4","after_hash":"4de067621814fec75fd8d58a54ae53427db6366198941342ee0249e9a604560a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2f9ffb620a5931ee9f7d3837ca3520c6dea774e1413efefcabb4970416c28424"} +{"hash_algorithm":"sha256","ts":"2026-10-18T05:09:33.936Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-10-18T05:09:33.934Z","author":"codex-agent","text":"Full npm gate attempt on 1b00e1b reached an existing regression timeout: SIGKILL at every HTTP-to-PM receipt boundary replays one decision per query exceeded its unchanged 300000 ms limit (300019.19627 ms). Its merged fix and prior measured evidence remain documented under pm-rl-bi4v. The new dataset cases passed 6/6 before this failure. Retain this failed attempt, inspect the completed result, and retry without extending deadlines or changing coverage thresholds; no passing full-gate claim is made."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:09:33.936Z"}],"before_hash":"4de067621814fec75fd8d58a54ae53427db6366198941342ee0249e9a604560a","after_hash":"615803d9b0dea34b406b94bef0bf2dded4d977275945205b3a111f6a69a63efa","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a7c8f8bcb99b5cbad35d856f8b38d5385512fdcec86be3779cf945885edd07ca"} +{"hash_algorithm":"sha256","ts":"2026-10-18T05:29:44.668Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/10","value":{"created_at":"2026-10-18T05:29:44.668Z","author":"codex-agent","text":"Draft PR #84 is open at 1b00e1b67c3fe7b6b396d28ecf6d8793843b3840. GitHub Node 26 CI passes 611/611, zero failures/skips, all 35 authored sources at statements/lines/branches/functions 100/100/100/100. The original eight-boundary HTTP SIGKILL drill passes there in 15884.547137 ms under its unchanged 300000 ms deadline. CodeQL passed; Node 22 remains running. Local npm remains a failed attempt because of the earlier timeout and is continuing for diagnostic coverage; local npm and Bun gates are still required. CodeRabbit explicitly skipped review of the draft, which is not approval evidence."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:29:44.668Z"}],"before_hash":"615803d9b0dea34b406b94bef0bf2dded4d977275945205b3a111f6a69a63efa","after_hash":"24d3707b5df880e6f41dd29f9a62112bb34e11c108a63843bdca30a32aa87e0c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"748b19695aeb05cf290d610a976362d0c9cbf926cb05ac8a833f62c037d5d9ba"} +{"hash_algorithm":"sha256","ts":"2026-10-18T05:34:27.178Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/17/path","value":"test/recipe.test.ts"},{"op":"replace","path":"/metadata/files/16/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/15/path","value":"test/fixtures/tracker-histories.json"},{"op":"replace","path":"/metadata/files/14/path","value":"test/fixtures/meta-workspace.ts"},{"op":"replace","path":"/metadata/files/13/path","value":"test/fixtures/meta-controller.ts"},{"op":"replace","path":"/metadata/files/12/path","value":"test/dataset.test.ts"},{"op":"replace","path":"/metadata/files/11/path","value":"scripts/live-watchdog.ts"},{"op":"replace","path":"/metadata/files/10/path","value":"scripts/live-meta.ts"},{"op":"replace","path":"/metadata/files/9/path","value":"recipe.ts"},{"op":"replace","path":"/metadata/files/8/path","value":"package.json"},{"op":"replace","path":"/metadata/files/7/path","value":"meta.ts"},{"op":"replace","path":"/metadata/files/6/path","value":"manifest.json"},{"op":"replace","path":"/metadata/files/5/path","value":"loop.ts"},{"op":"replace","path":"/metadata/files/4/path","value":"index.ts"},{"op":"replace","path":"/metadata/files/3/path","value":"examples/meta-trackers.json"},{"op":"replace","path":"/metadata/files/2/path","value":"examples/meta-approval.md"},{"op":"replace","path":"/metadata/files/1/path","value":"dataset.ts"},{"op":"replace","path":"/metadata/files/0/path","value":".github/workflows/ci.yml"},{"op":"add","path":"/metadata/files/18","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:34:27.178Z"}],"before_hash":"24d3707b5df880e6f41dd29f9a62112bb34e11c108a63843bdca30a32aa87e0c","after_hash":"d381a58b6b06b0bd95754a859fe6ccff40b5b6f84f7a68ea7c2434234ad1a0d2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"9cd357c2915331ef5814c02625f454811a0b32f335633384d95768d7acaf6250"} +{"hash_algorithm":"sha256","ts":"2026-10-18T05:34:31.818Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/11","value":{"created_at":"2026-10-18T05:34:31.818Z","author":"codex-agent","text":"Both original CI matrix jobs passed on 1b00e1b: Node 22 and 26 each 611/611, zero failures/skips, 35 sources at 100/100/100/100 and 295 documented declarations. To execute the exact required npm and Bun release commands reproducibly, CI now retains test (22) and test (26), adds Bun release (26), and invokes the full existing release:check script with isolated HOME and global/system Git configuration. No gate, deadline, source scope, threshold, dependency pin or release approval changed. The overloaded-host npm attempt was deliberately stopped after its recorded HTTP crash-drill timeout; its cancellation output is retained and is not passing evidence. Exact-command CI receipts remain pending."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:34:31.818Z"}],"before_hash":"d381a58b6b06b0bd95754a859fe6ccff40b5b6f84f7a68ea7c2434234ad1a0d2","after_hash":"a25347b351780fe63626898113324ac97da0378cf87ae4402000f5355f10a069","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"504c1f47a77a5c5abe857e853742794ea4ea69f8032b6d8726aee009be2746a0"} +{"hash_algorithm":"sha256","ts":"2026-10-18T05:36:06.534Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/12","value":{"created_at":"2026-10-18T05:36:06.534Z","author":"codex-agent","text":"The strengthened CI uses separate literal npm and Bun steps selected by the fixed matrix. The static publish-attestation gate correctly refused an unresolved dynamic executable during development; the literal version passes the verifier and all 8/8 attestation tests, zero skips. YAML parsing confirms exactly three intended combinations. Required Node check names, the Bun install check and read-only workflow permissions are preserved. Exact release-command CI now runs on the branch; release approval remains disabled."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:36:06.534Z"}],"before_hash":"a25347b351780fe63626898113324ac97da0378cf87ae4402000f5355f10a069","after_hash":"54b5e08d3c2e9239ea6786dd4da083b6569b7df6a573ae7b3765eab3e8159e55","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"5d623b93d996f2df10cda8384fc5595268081d6d1f7f43fa641b2195c4b88f25"} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e019a30e..67df35ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,13 +11,23 @@ permissions: jobs: test: + name: ${{ matrix.check-name }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: # 22 is the floor declared in `engines` and the first line that strips # TypeScript without a flag; 26 is what the fleet develops against. - node-version: [22, 26] + include: + - node-version: 22 + package-manager: npm + check-name: test (22) + - node-version: 26 + package-manager: npm + check-name: test (26) + - node-version: 26 + package-manager: bun + check-name: Bun release (26) steps: - name: Checkout uses: actions/checkout@v7 @@ -61,38 +71,21 @@ jobs: # still exiting successfully. ./node_modules/.bin/pm health --strict-exit --require-merge-drivers - - name: Type check - run: npm run typecheck - - - name: Build - run: npm run build - - - name: Lint - run: npm run lint - - - name: Check for duplicated code - run: npm run duplicates - - - name: Verify complete docstring coverage - run: npm run docstring - - - name: Verify every publish invocation is attested - run: npm run verify:release-publish-attestation - - - name: Test with coverage gate - run: npm run coverage - - - name: Audit commit identities against the approved list - run: npm run audit:identities - - - name: Production dependency audit - run: npm run audit:prod - - - name: Verify npm package contents - run: npm run pack:dry-run + - name: Run complete npm release gate with isolated identity + if: ${{ matrix.package-manager == 'npm' }} + shell: bash + run: | + set -euo pipefail + gate_home=$(mktemp -d) + env HOME="$gate_home" GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 npm run release:check - - name: Verify generated changelog - run: npm run changelog:check + - name: Run complete Bun release gate with isolated identity + if: ${{ matrix.package-manager == 'bun' }} + shell: bash + run: | + set -euo pipefail + gate_home=$(mktemp -d) + env HOME="$gate_home" GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 bun run release:check - name: Verify Bun can install the package graph run: bun install --no-save From c882cc2527ace62cff02af25a85b5bb30dedb2a4 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 08:03:22 +0200 Subject: [PATCH 03/24] fix: bind canonical programme identities to budget reservations --- .agents/pm/features/pm-rl-meta.toon | 9 ++++++--- .agents/pm/history/pm-rl-meta.jsonl | 3 +++ docs/meta-recursive.md | 5 ++++- meta.ts | 5 ++++- test/meta.test.ts | 16 ++++++++++++++++ 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 109623bb..7d1646b6 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T05:36:06.534Z" +updated_at: "2026-10-18T06:03:14.724Z" assignee: codex-agent claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[13]{created_at,author,text}: +comments[15]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -26,6 +26,8 @@ comments[13]{created_at,author,text}: "2026-10-18T05:29:44.668Z",codex-agent,"Draft PR #84 is open at 1b00e1b67c3fe7b6b396d28ecf6d8793843b3840. GitHub Node 26 CI passes 611/611, zero failures/skips, all 35 authored sources at statements/lines/branches/functions 100/100/100/100. The original eight-boundary HTTP SIGKILL drill passes there in 15884.547137 ms under its unchanged 300000 ms deadline. CodeQL passed; Node 22 remains running. Local npm remains a failed attempt because of the earlier timeout and is continuing for diagnostic coverage; local npm and Bun gates are still required. CodeRabbit explicitly skipped review of the draft, which is not approval evidence." "2026-10-18T05:34:31.818Z",codex-agent,"Both original CI matrix jobs passed on 1b00e1b: Node 22 and 26 each 611/611, zero failures/skips, 35 sources at 100/100/100/100 and 295 documented declarations. To execute the exact required npm and Bun release commands reproducibly, CI now retains test (22) and test (26), adds Bun release (26), and invokes the full existing release:check script with isolated HOME and global/system Git configuration. No gate, deadline, source scope, threshold, dependency pin or release approval changed. The overloaded-host npm attempt was deliberately stopped after its recorded HTTP crash-drill timeout; its cancellation output is retained and is not passing evidence. Exact-command CI receipts remain pending." "2026-10-18T05:36:06.534Z",codex-agent,"The strengthened CI uses separate literal npm and Bun steps selected by the fixed matrix. The static publish-attestation gate correctly refused an unresolved dynamic executable during development; the literal version passes the verifier and all 8/8 attestation tests, zero skips. YAML parsing confirms exactly three intended combinations. Required Node check names, the Bun install check and read-only workflow permissions are preserved. Exact release-command CI now runs on the branch; release approval remains disabled." + "2026-10-18T05:59:59.550Z",codex-agent,"A real SDK boundary probe found a concrete accounting defect: UPPER became a lowercase item id while its reservation body retained UPPER. A second programme then reserved another 1024 samples under a 1024-sample approval, before either fit. The fix rejects noncanonical programme ids before any write and case-folds retained ledger identities, so earlier uppercase allocations remain charged. Focused ledger regressions pass 4/4. Isolated behavioural revert proofs retain the new test: remove only the runRlMeta id guard and it fails 0/1 with noncanonical programme reached a write; restore it and remove only reserveMeta case folding and it fails 0/1 with retained allocation was hidden; restore both and it passes 1/1. Exact command: node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts. These are direct TypeScript source tests. Numerical training, data splits and statistical gates are unchanged. The previous three exact-command CI jobs passed 611/611 each on f622177, but that evidence predates this correction; full gates must rerun with 612 tests." + "2026-10-18T06:03:14.724Z",codex-agent,"Pinned-PM linked verification on the corrected tree passes 9/9 for node --test test/recipe.test.ts test/dataset.test.ts and 1/1 for node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts, zero failures/skips. The existing physical-kill, genuine-promotion and one-approval linked trio previously passed 3/3 and remains in the full suite. Test-result persistence remains disabled by project policy; comments retain the receipts. Build and test compilation, lint, duplicate detection and docstring verification pass: 35 source files, 295 documented declarations, zero clones. The documented approval-template CLI smoke also passes against a real tracker with a full Decision read." files[19]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project @@ -46,9 +48,10 @@ files[19]{path,scope}: test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[2]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[3]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop + "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop docs[6]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 44f7d926..0b8aaf11 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -26,3 +26,6 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T05:34:27.178Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/17/path","value":"test/recipe.test.ts"},{"op":"replace","path":"/metadata/files/16/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/15/path","value":"test/fixtures/tracker-histories.json"},{"op":"replace","path":"/metadata/files/14/path","value":"test/fixtures/meta-workspace.ts"},{"op":"replace","path":"/metadata/files/13/path","value":"test/fixtures/meta-controller.ts"},{"op":"replace","path":"/metadata/files/12/path","value":"test/dataset.test.ts"},{"op":"replace","path":"/metadata/files/11/path","value":"scripts/live-watchdog.ts"},{"op":"replace","path":"/metadata/files/10/path","value":"scripts/live-meta.ts"},{"op":"replace","path":"/metadata/files/9/path","value":"recipe.ts"},{"op":"replace","path":"/metadata/files/8/path","value":"package.json"},{"op":"replace","path":"/metadata/files/7/path","value":"meta.ts"},{"op":"replace","path":"/metadata/files/6/path","value":"manifest.json"},{"op":"replace","path":"/metadata/files/5/path","value":"loop.ts"},{"op":"replace","path":"/metadata/files/4/path","value":"index.ts"},{"op":"replace","path":"/metadata/files/3/path","value":"examples/meta-trackers.json"},{"op":"replace","path":"/metadata/files/2/path","value":"examples/meta-approval.md"},{"op":"replace","path":"/metadata/files/1/path","value":"dataset.ts"},{"op":"replace","path":"/metadata/files/0/path","value":".github/workflows/ci.yml"},{"op":"add","path":"/metadata/files/18","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:34:27.178Z"}],"before_hash":"24d3707b5df880e6f41dd29f9a62112bb34e11c108a63843bdca30a32aa87e0c","after_hash":"d381a58b6b06b0bd95754a859fe6ccff40b5b6f84f7a68ea7c2434234ad1a0d2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"9cd357c2915331ef5814c02625f454811a0b32f335633384d95768d7acaf6250"} {"hash_algorithm":"sha256","ts":"2026-10-18T05:34:31.818Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/11","value":{"created_at":"2026-10-18T05:34:31.818Z","author":"codex-agent","text":"Both original CI matrix jobs passed on 1b00e1b: Node 22 and 26 each 611/611, zero failures/skips, 35 sources at 100/100/100/100 and 295 documented declarations. To execute the exact required npm and Bun release commands reproducibly, CI now retains test (22) and test (26), adds Bun release (26), and invokes the full existing release:check script with isolated HOME and global/system Git configuration. No gate, deadline, source scope, threshold, dependency pin or release approval changed. The overloaded-host npm attempt was deliberately stopped after its recorded HTTP crash-drill timeout; its cancellation output is retained and is not passing evidence. Exact-command CI receipts remain pending."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:34:31.818Z"}],"before_hash":"d381a58b6b06b0bd95754a859fe6ccff40b5b6f84f7a68ea7c2434234ad1a0d2","after_hash":"a25347b351780fe63626898113324ac97da0378cf87ae4402000f5355f10a069","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"504c1f47a77a5c5abe857e853742794ea4ea69f8032b6d8726aee009be2746a0"} {"hash_algorithm":"sha256","ts":"2026-10-18T05:36:06.534Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/12","value":{"created_at":"2026-10-18T05:36:06.534Z","author":"codex-agent","text":"The strengthened CI uses separate literal npm and Bun steps selected by the fixed matrix. The static publish-attestation gate correctly refused an unresolved dynamic executable during development; the literal version passes the verifier and all 8/8 attestation tests, zero skips. YAML parsing confirms exactly three intended combinations. Required Node check names, the Bun install check and read-only workflow permissions are preserved. Exact release-command CI now runs on the branch; release approval remains disabled."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:36:06.534Z"}],"before_hash":"a25347b351780fe63626898113324ac97da0378cf87ae4402000f5355f10a069","after_hash":"54b5e08d3c2e9239ea6786dd4da083b6569b7df6a573ae7b3765eab3e8159e55","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"5d623b93d996f2df10cda8384fc5595268081d6d1f7f43fa641b2195c4b88f25"} +{"hash_algorithm":"sha256","ts":"2026-10-18T05:59:59.550Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/13","value":{"created_at":"2026-10-18T05:59:59.550Z","author":"codex-agent","text":"A real SDK boundary probe found a concrete accounting defect: UPPER became a lowercase item id while its reservation body retained UPPER. A second programme then reserved another 1024 samples under a 1024-sample approval, before either fit. The fix rejects noncanonical programme ids before any write and case-folds retained ledger identities, so earlier uppercase allocations remain charged. Focused ledger regressions pass 4/4. Isolated behavioural revert proofs retain the new test: remove only the runRlMeta id guard and it fails 0/1 with noncanonical programme reached a write; restore it and remove only reserveMeta case folding and it fails 0/1 with retained allocation was hidden; restore both and it passes 1/1. Exact command: node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts. These are direct TypeScript source tests. Numerical training, data splits and statistical gates are unchanged. The previous three exact-command CI jobs passed 611/611 each on f622177, but that evidence predates this correction; full gates must rerun with 612 tests."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:59:59.550Z"}],"before_hash":"54b5e08d3c2e9239ea6786dd4da083b6569b7df6a573ae7b3765eab3e8159e55","after_hash":"1a8ce725fcc97ff5937782d691042f94560db37f366fff633056fa5bc9143444","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e5a98107f8346ee20266a8af4a7e1a9535c19594e2bcef2796628d756ba1e491"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:00:04.512Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/2","value":{"command":"node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T06:00:04.075Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:00:04.512Z"}],"before_hash":"1a8ce725fcc97ff5937782d691042f94560db37f366fff633056fa5bc9143444","after_hash":"2b312bb75d35a6997159e9b6bb2e266d030b6273c20385efc8848fd8d0ed677d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"7c39e45acfdc68ba0cbc2cc34a66992d31c0c9e60390aa7939fa8adfb625b063"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:03:14.724Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/14","value":{"created_at":"2026-10-18T06:03:14.724Z","author":"codex-agent","text":"Pinned-PM linked verification on the corrected tree passes 9/9 for node --test test/recipe.test.ts test/dataset.test.ts and 1/1 for node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts, zero failures/skips. The existing physical-kill, genuine-promotion and one-approval linked trio previously passed 3/3 and remains in the full suite. Test-result persistence remains disabled by project policy; comments retain the receipts. Build and test compilation, lint, duplicate detection and docstring verification pass: 35 source files, 295 documented declarations, zero clones. The documented approval-template CLI smoke also passes against a real tracker with a full Decision read."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:03:14.724Z"}],"before_hash":"2b312bb75d35a6997159e9b6bb2e266d030b6273c20385efc8848fd8d0ed677d","after_hash":"620a899e58b8e2a926b95545d11348a9b02552816a4dede5483968454eac9f66","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"9ea65af38e3a8a13633faac260cb146b06c0b9059a439533893016e2c311e9b8"} diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index afb55116..10222d1b 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -23,7 +23,10 @@ public-history environment and a deliberately limited numerical learner; it does not demonstrate language-model training on tracker text. `pm rl meta run --file examples/meta-trackers.json --dataset ---approval ` executes or resumes the same programme. Its initial recipe +--approval ` executes or resumes the same programme. Programme ids use lowercase letters or +digits separated by single hyphens; noncanonical ids refuse before any write. +Retained reservation identities are compared using the SDK's case folding, so +an older uppercase spelling cannot hide an allocation. Its initial recipe is a versioned content-addressed artifact. Numeric domains cover learning rate, inner steps, batch, temperature and correct/incorrect reward weights. Categorical domains cover balanced/all selection and forward/reverse curriculum. Steps bound diff --git a/meta.ts b/meta.ts index db05db6f..b52d1f2c 100644 --- a/meta.ts +++ b/meta.ts @@ -119,7 +119,9 @@ async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, re const charges: Record[] = []; for (const item of items.items.filter((entry) => entry.type === "Decision" && entry.id.endsWith("-reservation"))) { const record = metaReservation(String((await readCompleteLoopItem(client, item.id)).item.body)); - if (record !== null && (item.id === record.id || item.id.endsWith(`-${record.id}`)) && record.approval === approval.id) { + if (record === null) continue; + const identity = record.id.toLowerCase(); + if ((item.id === identity || item.id.endsWith(`-${identity}`)) && record.approval === approval.id) { for (const key of ["training_samples", "proposal_calls", "recipe_promotions"]) { assert.ok(Number.isSafeInteger(record.charge[key]) && record.charge[key] >= 0, "meta_reservation_charge"); } @@ -209,6 +211,7 @@ export async function durableRecipeProposals(client: PmClient, id: string, reque /** Search and promote recipes with one shared approval; completion receipts adopt inner jobs after interruption. */ export async function runRlMeta(client: PmClient, coordinates: ProcessCoordinates, request: MetaRequest): Promise { + assert.match(request.id, /^[a-z0-9]+(?:-[a-z0-9]+)*$/, "meta_programme_id"); const config = parseMetaConfig(request.config); assert.ok(request.proposer === "seeded" || request.proposer === "decision-model", "meta_proposer"); const signal = request.signal === undefined ? AbortSignal.timeout(config.timeout_ms) : AbortSignal.any([request.signal, AbortSignal.timeout(config.timeout_ms)]); diff --git a/test/meta.test.ts b/test/meta.test.ts index ff3f93cd..5a6350e0 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -7,6 +7,7 @@ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { test } from "node:test"; import { createExtensionTestHarness } from "@unbrained/pm-cli/sdk/testing"; +import { certifyCompleteListResult } from "@unbrained/pm-cli/sdk/runtime"; import extension, { hashJson, withRlController, type JsonValue, type RlCommandResult } from "../index.ts"; import { compareRecipes, durableRecipeProposals, metaReservation, parseMetaConfig, proposeRecipes, recipeExamples, recipeSuccessor, runRlMeta, scoreTrackerPolicy, type MetaConfig, type MetaRequest } from "../meta.ts"; import { INITIAL_RECIPE, recipeArtifact, seededRecipes } from "../recipe.ts"; @@ -159,6 +160,21 @@ test("an interrupted atomic search reservation is retained once, including drift await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, approval: task.item.id }), /meta_approval_required/); }); +test("programme identity cannot hide approval reservations through SDK case folding", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const request = requestFor(w, "canonical", { ...metaConfig, meta_generations: 1, candidates: 1 }); + const spec = { ...metaSpec, meta_budget: { training_samples: 1024, proposal_calls: 0, recipe_promotions: 1 } }; + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify(spec)}\n\`\`\`` }); + for (const id of ["UPPER", "under_score", "", "../outside"]) { + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, id, onStep() { throw new Error("noncanonical programme reached a write"); } }), /meta_programme_id/); + } + assert.equal(certifyCompleteListResult(await w.client.listAllComplete({ includeBody: false })).items.length, 1, "invalid identities leave only the approval"); + await w.client.create({ id: "LEGACY-reservation", type: "Decision", title: "Retained case-folded allocation", body: JSON.stringify({ + format: "pm-rl/meta-reservation/1", id: "LEGACY-reservation", approval: w.approval, + charge: { training_samples: 1024, proposal_calls: 0, recipe_promotions: 1 }, + }) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, onStep() { throw new Error("retained allocation was hidden"); } }), /meta_budget_exhausted/); +}); + test("two distinct outer programmes cannot oversubscribe one approved search reservation", { timeout: 600_000 }, async () => { const w = await metaWorkspace(); const spec = { ...metaSpec, meta_budget: { training_samples: 1024, proposal_calls: 0, recipe_promotions: 1 } }; From 445b2327b4f60a0b7f183e7c6195f7d883b41c53 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 08:39:35 +0200 Subject: [PATCH 04/24] test: make Compose LM resource faults deterministic --- .agents/pm/features/pm-rl-meta.toon | 15 +++++++++++---- .agents/pm/features/pm-rl-whrd.toon | 11 ++++++++--- .agents/pm/history/pm-rl-meta.jsonl | 5 +++++ .agents/pm/history/pm-rl-whrd.jsonl | 4 ++++ docs/meta-live-evidence.json | 4 +++- docs/meta-recursive.md | 2 +- test/fixtures/lm-compose-memory.ts | 14 ++++++++++++++ test/fixtures/lm-compose-trainer.ts | 25 ++++++++++++++----------- test/fixtures/lm-compose.Dockerfile | 4 ++-- test/lm-compose.test.ts | 20 +++++++++++++++----- 10 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 test/fixtures/lm-compose-memory.ts diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 7d1646b6..00fdc32f 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T06:03:14.724Z" +updated_at: "2026-10-18T06:39:15.630Z" assignee: codex-agent claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[15]{created_at,author,text}: +comments[17]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -28,7 +28,9 @@ comments[15]{created_at,author,text}: "2026-10-18T05:36:06.534Z",codex-agent,"The strengthened CI uses separate literal npm and Bun steps selected by the fixed matrix. The static publish-attestation gate correctly refused an unresolved dynamic executable during development; the literal version passes the verifier and all 8/8 attestation tests, zero skips. YAML parsing confirms exactly three intended combinations. Required Node check names, the Bun install check and read-only workflow permissions are preserved. Exact release-command CI now runs on the branch; release approval remains disabled." "2026-10-18T05:59:59.550Z",codex-agent,"A real SDK boundary probe found a concrete accounting defect: UPPER became a lowercase item id while its reservation body retained UPPER. A second programme then reserved another 1024 samples under a 1024-sample approval, before either fit. The fix rejects noncanonical programme ids before any write and case-folds retained ledger identities, so earlier uppercase allocations remain charged. Focused ledger regressions pass 4/4. Isolated behavioural revert proofs retain the new test: remove only the runRlMeta id guard and it fails 0/1 with noncanonical programme reached a write; restore it and remove only reserveMeta case folding and it fails 0/1 with retained allocation was hidden; restore both and it passes 1/1. Exact command: node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts. These are direct TypeScript source tests. Numerical training, data splits and statistical gates are unchanged. The previous three exact-command CI jobs passed 611/611 each on f622177, but that evidence predates this correction; full gates must rerun with 612 tests." "2026-10-18T06:03:14.724Z",codex-agent,"Pinned-PM linked verification on the corrected tree passes 9/9 for node --test test/recipe.test.ts test/dataset.test.ts and 1/1 for node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts, zero failures/skips. The existing physical-kill, genuine-promotion and one-approval linked trio previously passed 3/3 and remains in the full suite. Test-result persistence remains disabled by project policy; comments retain the receipts. Build and test compilation, lint, duplicate detection and docstring verification pass: 35 source files, 295 documented declarations, zero clones. The documented approval-template CLI smoke also passes against a real tracker with a full Decision read." -files[19]{path,scope}: + "2026-10-18T06:08:25.887Z",codex-agent,"Corrected-source live acceptance PASS on c882cc2527ace62cff02af25a85b5bb30dedb2a4: npm run test:live reproduced the complete real dataset manifest and report exactly. Two meta-generations, K=2, 25 public MIT repositories, 1767 examples (1023 train, 145 inner held-out, 214 meta-validation, 385 final-test). Incumbent b77fdfeff48d; candidates 800886e9f4cd, 45113586500f, 4a48567235f1 and 55539a90ca05 all score 107/214, gain 0, lower gain bound -0.21778781183411927; none promoted. Final-test before/after remains 198/385=0.5142857142857142. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c. Dataset/controller elapsed 92238.67339099999 ms within the unchanged 15-minute watchdog. Source identity is recorded in docs/meta-live-evidence.json. Recipe, bounds, seed, approvals, splits and statistical settings were not tuned after final-test exposure. Current full CI is still running with 612 tests." + "2026-10-18T06:39:15.630Z",codex-agent,"The corrected production source c882cc2 passed the full Bun release gate 612/612, zero failures/skips, all 35 required sources at 100/100/100/100 and 295 documented declarations. The Node 22 and Node 26 jobs each failed only the existing Compose LM resource drill, respectively missing native OOM evidence and collecting a second Run. Those fault-injection assumptions are now explicit and bounded, tracked with pm-rl-whrd: native allocator and deadline barrier with unchanged limits/assertions. Both fixture-only behavioural reverts fail 0/1; restored physical and PM-linked checks pass 1/1 each. Linked feature tests now cover 9/9 data/recipe, 3/3 core crash/promotion/budget, 1/1 canonical identity and 1/1 real resource refusal. Production training, recipe bounds, splits and statistical promotion are unchanged. The complete 612-test npm/Bun CI matrix must pass on the forthcoming commit; no passing npm result is claimed for c882cc2." +files[23]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project examples/meta-approval.md,project @@ -42,16 +44,21 @@ files[19]{path,scope}: scripts/live-meta.ts,project scripts/live-watchdog.ts,project test/dataset.test.ts,project + test/fixtures/lm-compose-memory.ts,project + test/fixtures/lm-compose-trainer.ts,project + test/fixtures/lm-compose.Dockerfile,project test/fixtures/meta-controller.ts,project test/fixtures/meta-workspace.ts,project test/fixtures/tracker-histories.json,project + test/lm-compose.test.ts,project test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[3]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[4]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop + "node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts",project,600,codex-agent,"2026-10-18T06:35:18.894Z",local_mutation,feat/meta-recursive-recipe-loop docs[6]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/features/pm-rl-whrd.toon b/.agents/pm/features/pm-rl-whrd.toon index f43e1104..68dc53af 100644 --- a/.agents/pm/features/pm-rl-whrd.toon +++ b/.agents/pm/features/pm-rl-whrd.toon @@ -6,11 +6,13 @@ status: in_progress priority: 2 tags[3]: execution,llm-adapter,recursive-training created_at: "2026-10-15T22:07:13.392Z" -updated_at: "2026-10-18T03:01:06.851Z" +updated_at: "2026-10-18T06:39:11.323Z" +assignee: codex-agent +claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two real generations with successor collection; SIGKILL recovery, cancellation, corrupt checkpoint and limit refusals, one-launch contention; behavioural revert proofs and unchanged npm and Bun release gates." parent: pm-rl-apvf -comments[24]{created_at,author,text}: +comments[26]{created_at,author,text}: "2026-10-15T22:07:43.111Z",codex-agent,"Design: extend the existing process contract with a typed LM payload and checkpoint validator; share owner fences, atomic reservation, staged adoption, cancellation and settlement. Keep held-out examples in the controller. Bind immutable image, memory and CPU ceilings into programme and job identity; send only frozen weights, source adapter, training strings and collected rewards to a networkless non-root container. Add real recursive generations and crash/cancellation/limit/contention drills, then behavioural revert proofs and unchanged release gates." "2026-10-15T22:16:06.750Z",codex-agent,"First real Compose evidence: generation 1 checkpoint 058aa3d2c08438abd18cf0e9b455aca99ddb95492de852201c55c79a0672130d -> 37e503748a170be32e1d506997b6c0cc5c9ee256b24ab01fb49cf0564da07b4c; held-out sampled reward 0.183854, six steps, 1152 target tokens, observed wall 5567 ms, fit CPU 820 ms, peak RSS 138629120 bytes, retained staging 88930 bytes. Generation 2 collected with that promoted digest and trained -> 086f78992283cba37929321abe3961ca6132a52c332bf8a8387a52f22141cbdb; reward 0.292396, six steps, 1152 tokens, wall 5654 ms, CPU 803 ms, peak RSS 143323136 bytes, staging 92364 bytes. Both promoted through the existing gate. Real controller SIGKILL after completion before receipt commit recovered the same checkpoint and original reservation with one launch. Mid-fit cancellation retained input/events and process_cancelled. Full drills and coverage verification continue. The first linked run reached its default 120-second timeout; rerun will explicitly allow the complete integration duration." "2026-10-15T22:24:09.789Z",codex-agent,"Validated linked run: pm test pm-rl-whrd --run --progress --timeout 900 passed 8/8, zero failures/skips/cancellations/todo. Real kernel memory drill retained partial allocation evidence and daemon oom_killed=true at 201326592 bytes; the time drill began the real 1000-step fit before exceeding its 15000 ms allowance. Both refused promotion and successor collection. Two-generation execution took 54134.161 ms; independent verification/replay/status took 4470.981 ms. Canonical hashes and held-out objectives match the first measurement. Final fit resources: generation 1 wall 4297 ms, CPU 713 ms, RSS 138207232 bytes, staging 89057 bytes; generation 2 wall 4266 ms, CPU 759 ms, RSS 144183296 bytes, staging 92509 bytes; both six steps and 1152 target tokens. Daemon receipts verify memory=268435456, CPU=1, no network and non-root user. Existing Compose barrier variability is tracked in pm-rl-8nev. Revert proofs and complete release gates remain in progress." @@ -35,7 +37,9 @@ comments[24]{created_at,author,text}: "2026-10-16T05:51:23.733Z",codex-agent,"Extended CI parity: the failed GitHub job used Node 26.12.0, while initially installed Node 26 was 26.7.0. Installed the exact 26.12.0 runtime with verified download checksum. Three diagnostic original-source contention probes also passed on 26.12.0, so the historical refusal remains unconfirmed. The final synchronized test now independently passes 20/20 on each of Node 22.23.1, 26.7.0 and 26.12.0 (60/60, zero failures/skips). Re-fetched main; it remains an ancestor, so no merge is needed. Literal Bun release gate at source 91d40fc passes 590/590, zero failures/skips/cancellations, all four coverage dimensions 100% across 30 sources, 272 documented declarations, and all audit/package/changelog checks. First npm attempt retains 589/590 with only the packed CLI child reaching its unchanged 25000 ms timeout; concurrent diagnostic probes added load, so that attempt is not passing gate evidence. Serial npm retry is now running alone on exact CI Node 26.12.0." "2026-10-16T06:12:44.947Z",codex-agent,"Final local delivery at source/test commit 91d40fc: literal npm run release:check on Node 26.12.0 exits 0 with 590/590 passing, zero failed/skipped/cancelled, all four coverage dimensions 100% over all 30 sources, 272 documented declarations, and identity/audit/package/changelog checks passed. Literal bun run release:check on Node 26.7.0 and Bun 1.3.5 also exits 0 with 590/590 and the same unchanged four 100% thresholds. Packed CLI measured 10996.891 ms (npm retry) and 11086.851 ms (Bun). Preserve the first npm attempt: 589/590, sole unchanged 25000 ms packed CLI timeout; it is not passing gate evidence. Final contention loops are 20/20 each on Node 22.23.1, 26.7.0 and exact CI 26.12.0. The original CI winner refusal cannot be recovered from its log and did not reproduce; the reservation barrier invariant is proved, but the historical timeout root cause remains unconfirmed. Cleanup independently verifies zero repository Compose containers, and three owned validation images were removed after checking their exact owner label. Original history byte prefixes remain unchanged for both touched items. Main is already an ancestor; ready to push and wait for GitHub checks, without merging or resolving threads." "2026-10-18T03:01:05.676Z",codex-agent,"Audit: MET against recorded acceptance. Merged PR #80 (b255dfac6543ab178ab2720fad1de1ba49f91dd4) supplies two real external LM generations and successor collection, SIGKILL staged-completion recovery without retraining or double charge, cancellation, corrupt checkpoint and resource refusals, and one-launch contention. docs/lm-adapter.md and test/lm-compose.test.ts retain measured evidence; feature and fixture behavioural revert proofs are recorded. Final isolated npm and Bun release gates each passed 590/590 with exact four-metric 100% coverage. No acceptance gap found in merged evidence; storage kernel enforcement remains separately tracked in pm-rl-7073. Leave open for orchestrator verification." -files[20]{path,scope}: + "2026-10-18T06:19:59.564Z",codex-agent,"Current meta-feature CI exposed a timing-dependent existing fault drill: the Node 26 job observed two collection Runs instead of one in the corrupt/memory/time test, while every authored source reported 100% lines/branches/functions. The time case assumed 1000 real LM fit steps necessarily exceeded 15000 ms; that assumption depends on runner speed. The correction selects a time-only fixture that enters the actual packaged LM trainer, publishes its genuine zero-step progress, retains a barrier marker and blocks before numerical fit until the unchanged process deadline terminates the container. Corrupt and memory modes, the 15000 ms allowance, every existing failure/no-successor/cleanup/resume assertion, production training and promotion criteria remain unchanged. Focused physical verification and full gates are pending. The earlier merged acceptance audit remains historical evidence, not a passing result for this new attempt." + "2026-10-18T06:39:11.323Z",codex-agent,"Resource-drill stabilization verified physically: the deadline fixture forwards the genuine packaged LM zero-step progress and blocks before fit; the unchanged 15000 ms guard kills it. The separate minimal allocator records its V8 heap ceiling above the unchanged 201326592-byte cgroup cap, then causes a native Docker OOM; the OOMKilled assertion is preserved. Every existing failed/settled/no-completion/one-Run/no-promoted-generation/retained-input/event/container-removal/resume-refusal assertion remains. Focused restored test passes 1/1. In an isolated source snapshot, reverting only memory-worker dispatch fails 0/1 with Missing expected rejection for memory; reverting only the time barrier fails 0/1 with missing time-barrier evidence; restoring both passes 1/1. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. The PM-linked run also passes 1/1, zero skips. Build:test, lint and static publish attestation pass. Full CI must rerun; leave in progress for orchestrator verification." +files[21]{path,scope}: .dockerignore,project compose.ts,project index.ts,project @@ -52,6 +56,7 @@ files[20]{path,scope}: test/durable-loop.test.ts,project test/fixtures/compose.Dockerfile,project test/fixtures/decision-controller.ts,project + test/fixtures/lm-compose-memory.ts,project test/fixtures/lm-compose-trainer.ts,project test/fixtures/lm-compose.Dockerfile,project test/fixtures/process-controller.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 0b8aaf11..b8b9e38a 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -29,3 +29,8 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T05:59:59.550Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/13","value":{"created_at":"2026-10-18T05:59:59.550Z","author":"codex-agent","text":"A real SDK boundary probe found a concrete accounting defect: UPPER became a lowercase item id while its reservation body retained UPPER. A second programme then reserved another 1024 samples under a 1024-sample approval, before either fit. The fix rejects noncanonical programme ids before any write and case-folds retained ledger identities, so earlier uppercase allocations remain charged. Focused ledger regressions pass 4/4. Isolated behavioural revert proofs retain the new test: remove only the runRlMeta id guard and it fails 0/1 with noncanonical programme reached a write; restore it and remove only reserveMeta case folding and it fails 0/1 with retained allocation was hidden; restore both and it passes 1/1. Exact command: node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts. These are direct TypeScript source tests. Numerical training, data splits and statistical gates are unchanged. The previous three exact-command CI jobs passed 611/611 each on f622177, but that evidence predates this correction; full gates must rerun with 612 tests."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T05:59:59.550Z"}],"before_hash":"54b5e08d3c2e9239ea6786dd4da083b6569b7df6a573ae7b3765eab3e8159e55","after_hash":"1a8ce725fcc97ff5937782d691042f94560db37f366fff633056fa5bc9143444","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e5a98107f8346ee20266a8af4a7e1a9535c19594e2bcef2796628d756ba1e491"} {"hash_algorithm":"sha256","ts":"2026-10-18T06:00:04.512Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/2","value":{"command":"node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T06:00:04.075Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:00:04.512Z"}],"before_hash":"1a8ce725fcc97ff5937782d691042f94560db37f366fff633056fa5bc9143444","after_hash":"2b312bb75d35a6997159e9b6bb2e266d030b6273c20385efc8848fd8d0ed677d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"7c39e45acfdc68ba0cbc2cc34a66992d31c0c9e60390aa7939fa8adfb625b063"} {"hash_algorithm":"sha256","ts":"2026-10-18T06:03:14.724Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/14","value":{"created_at":"2026-10-18T06:03:14.724Z","author":"codex-agent","text":"Pinned-PM linked verification on the corrected tree passes 9/9 for node --test test/recipe.test.ts test/dataset.test.ts and 1/1 for node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts, zero failures/skips. The existing physical-kill, genuine-promotion and one-approval linked trio previously passed 3/3 and remains in the full suite. Test-result persistence remains disabled by project policy; comments retain the receipts. Build and test compilation, lint, duplicate detection and docstring verification pass: 35 source files, 295 documented declarations, zero clones. The documented approval-template CLI smoke also passes against a real tracker with a full Decision read."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:03:14.724Z"}],"before_hash":"2b312bb75d35a6997159e9b6bb2e266d030b6273c20385efc8848fd8d0ed677d","after_hash":"620a899e58b8e2a926b95545d11348a9b02552816a4dede5483968454eac9f66","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"9ea65af38e3a8a13633faac260cb146b06c0b9059a439533893016e2c311e9b8"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:08:25.887Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/15","value":{"created_at":"2026-10-18T06:08:25.887Z","author":"codex-agent","text":"Corrected-source live acceptance PASS on c882cc2527ace62cff02af25a85b5bb30dedb2a4: npm run test:live reproduced the complete real dataset manifest and report exactly. Two meta-generations, K=2, 25 public MIT repositories, 1767 examples (1023 train, 145 inner held-out, 214 meta-validation, 385 final-test). Incumbent b77fdfeff48d; candidates 800886e9f4cd, 45113586500f, 4a48567235f1 and 55539a90ca05 all score 107/214, gain 0, lower gain bound -0.21778781183411927; none promoted. Final-test before/after remains 198/385=0.5142857142857142. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c. Dataset/controller elapsed 92238.67339099999 ms within the unchanged 15-minute watchdog. Source identity is recorded in docs/meta-live-evidence.json. Recipe, bounds, seed, approvals, splits and statistical settings were not tuned after final-test exposure. Current full CI is still running with 612 tests."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:08:25.887Z"}],"before_hash":"620a899e58b8e2a926b95545d11348a9b02552816a4dede5483968454eac9f66","after_hash":"238051a71f1f32260d0601d313289a99838deb270a123ffdff65f74caf06d55e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"da607ec42a4d88e0c9a219f56d13ea3055cd6c5629957b3834e804001df65539"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:20:00.950Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/18/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/17/path","value":"test/lm-compose.test.ts"},{"op":"replace","path":"/metadata/files/16/path","value":"test/fixtures/tracker-histories.json"},{"op":"replace","path":"/metadata/files/15/path","value":"test/fixtures/meta-workspace.ts"},{"op":"replace","path":"/metadata/files/14/path","value":"test/fixtures/meta-controller.ts"},{"op":"replace","path":"/metadata/files/13/path","value":"test/fixtures/lm-compose-trainer.ts"},{"op":"add","path":"/metadata/files/19","value":{"path":"test/recipe.test.ts","scope":"project"}},{"op":"add","path":"/metadata/files/20","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:20:00.950Z"}],"before_hash":"238051a71f1f32260d0601d313289a99838deb270a123ffdff65f74caf06d55e","after_hash":"f7a706fbae7bac81bfb8394034a2a11cd2e0214a6e1527fd6401e389ca822b59","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"a5f2380c92c52e2329e4ecb576793e73e7b87d6a3542c33a4b7312b44a999908"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:35:11.981Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/20/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/19/path","value":"test/lm-compose.test.ts"},{"op":"replace","path":"/metadata/files/18/path","value":"test/fixtures/tracker-histories.json"},{"op":"replace","path":"/metadata/files/17/path","value":"test/fixtures/meta-workspace.ts"},{"op":"replace","path":"/metadata/files/16/path","value":"test/fixtures/meta-controller.ts"},{"op":"replace","path":"/metadata/files/15/path","value":"test/fixtures/lm-compose.Dockerfile"},{"op":"replace","path":"/metadata/files/14/path","value":"test/fixtures/lm-compose-trainer.ts"},{"op":"replace","path":"/metadata/files/13/path","value":"test/fixtures/lm-compose-memory.ts"},{"op":"add","path":"/metadata/files/21","value":{"path":"test/recipe.test.ts","scope":"project"}},{"op":"add","path":"/metadata/files/22","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:35:11.981Z"}],"before_hash":"f7a706fbae7bac81bfb8394034a2a11cd2e0214a6e1527fd6401e389ca822b59","after_hash":"d7de1c581ed048c7e09e4f34408ed947daede7ff991270e8b58560ee432d4af9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"87e54a7ffebf1fe4c07ed1f14ac0dfc67d4507b873f53098f33246104c1f856e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:35:19.054Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/3","value":{"command":"node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T06:35:18.894Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:35:19.054Z"}],"before_hash":"d7de1c581ed048c7e09e4f34408ed947daede7ff991270e8b58560ee432d4af9","after_hash":"01e08f20abee94cab6d5086614cb4d622988cd61fd8f763efb4c49aeac775f34","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"46491d3dafb1e80d0ee13051842dd2b5299409eeb8a6244fe2cf865d2d2c89dc"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:39:15.630Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/16","value":{"created_at":"2026-10-18T06:39:15.630Z","author":"codex-agent","text":"The corrected production source c882cc2 passed the full Bun release gate 612/612, zero failures/skips, all 35 required sources at 100/100/100/100 and 295 documented declarations. The Node 22 and Node 26 jobs each failed only the existing Compose LM resource drill, respectively missing native OOM evidence and collecting a second Run. Those fault-injection assumptions are now explicit and bounded, tracked with pm-rl-whrd: native allocator and deadline barrier with unchanged limits/assertions. Both fixture-only behavioural reverts fail 0/1; restored physical and PM-linked checks pass 1/1 each. Linked feature tests now cover 9/9 data/recipe, 3/3 core crash/promotion/budget, 1/1 canonical identity and 1/1 real resource refusal. Production training, recipe bounds, splits and statistical promotion are unchanged. The complete 612-test npm/Bun CI matrix must pass on the forthcoming commit; no passing npm result is claimed for c882cc2."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:39:15.630Z"}],"before_hash":"01e08f20abee94cab6d5086614cb4d622988cd61fd8f763efb4c49aeac775f34","after_hash":"4ba5019dd7d496c47ed2b7c33cd01ee1a5aec666575fc5f786c8f642d1adbec4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"57203ad1335d8b29fbdd0ddfe6ff00c2c8d73d3b5afd02f087c8d34ade94f892"} diff --git a/.agents/pm/history/pm-rl-whrd.jsonl b/.agents/pm/history/pm-rl-whrd.jsonl index c74622f9..f84fa642 100644 --- a/.agents/pm/history/pm-rl-whrd.jsonl +++ b/.agents/pm/history/pm-rl-whrd.jsonl @@ -42,3 +42,7 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T03:01:03.019Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:03.019Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"30b0dd19789308a01bfab726a63188834f14bd2c6a5887b5c650f91cf2e08e33","after_hash":"9a13046fe34590389b172bbe47314784d192ed1563e486033eda92fae3e17829","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e81d619b73de97e750152eecf384156febd3570b9027bdf1f2e063031731dbb5"} {"hash_algorithm":"sha256","ts":"2026-10-18T03:01:05.676Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/23","value":{"created_at":"2026-10-18T03:01:05.676Z","author":"codex-agent","text":"Audit: MET against recorded acceptance. Merged PR #80 (b255dfac6543ab178ab2720fad1de1ba49f91dd4) supplies two real external LM generations and successor collection, SIGKILL staged-completion recovery without retraining or double charge, cancellation, corrupt checkpoint and resource refusals, and one-launch contention. docs/lm-adapter.md and test/lm-compose.test.ts retain measured evidence; feature and fixture behavioural revert proofs are recorded. Final isolated npm and Bun release gates each passed 590/590 with exact four-metric 100% coverage. No acceptance gap found in merged evidence; storage kernel enforcement remains separately tracked in pm-rl-7073. Leave open for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:05.676Z"}],"before_hash":"9a13046fe34590389b172bbe47314784d192ed1563e486033eda92fae3e17829","after_hash":"f0db1203551b4fffe4f7cf0e615fd1fedfb3746fb9d9cae885d714b1106948a9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a2825b08164844101c109aae6748dd047b5887a4fc602e8d7d4dcaf46bcb93d3"} {"hash_algorithm":"sha256","ts":"2026-10-18T03:01:06.851Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T03:01:06.851Z"}],"before_hash":"f0db1203551b4fffe4f7cf0e615fd1fedfb3746fb9d9cae885d714b1106948a9","after_hash":"b706e3d807672f71be9886b8b269387f16fc52f145a3175316e212cd5a3e685e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"6928c08c6712a4a68e78f2598b68e21a48557b8c77f837af7041da8771de0420"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:19:58.231Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:19:58.231Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"b706e3d807672f71be9886b8b269387f16fc52f145a3175316e212cd5a3e685e","after_hash":"0a669565cd9ddf815ae74ecdff1aa1a55224554f3f4af5c95812c02d4d0e89bb","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"4a24e4df5f2dd655520ceb4acd0da2103c3631237931e671ebb13186365a4df3"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:19:59.564Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/24","value":{"created_at":"2026-10-18T06:19:59.564Z","author":"codex-agent","text":"Current meta-feature CI exposed a timing-dependent existing fault drill: the Node 26 job observed two collection Runs instead of one in the corrupt/memory/time test, while every authored source reported 100% lines/branches/functions. The time case assumed 1000 real LM fit steps necessarily exceeded 15000 ms; that assumption depends on runner speed. The correction selects a time-only fixture that enters the actual packaged LM trainer, publishes its genuine zero-step progress, retains a barrier marker and blocks before numerical fit until the unchanged process deadline terminates the container. Corrupt and memory modes, the 15000 ms allowance, every existing failure/no-successor/cleanup/resume assertion, production training and promotion criteria remain unchanged. Focused physical verification and full gates are pending. The earlier merged acceptance audit remains historical evidence, not a passing result for this new attempt."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:19:59.564Z"}],"before_hash":"0a669565cd9ddf815ae74ecdff1aa1a55224554f3f4af5c95812c02d4d0e89bb","after_hash":"63f05069e58977aa2015ff40818bce5a4858d51411a6efd1b9ec77cf75a72956","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2abc2a1d39241bc710e3b1f5d86b43b9997f4cefb1c0bacefe05604e0a4955d9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:35:15.670Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/19/path","value":"test/fixtures/process-controller.ts"},{"op":"replace","path":"/metadata/files/18/path","value":"test/fixtures/lm-compose.Dockerfile"},{"op":"replace","path":"/metadata/files/17/path","value":"test/fixtures/lm-compose-trainer.ts"},{"op":"replace","path":"/metadata/files/16/path","value":"test/fixtures/lm-compose-memory.ts"},{"op":"add","path":"/metadata/files/20","value":{"path":"test/lm-compose.test.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:35:15.670Z"}],"before_hash":"63f05069e58977aa2015ff40818bce5a4858d51411a6efd1b9ec77cf75a72956","after_hash":"3481c36d0d5ca47685b7d688f30808812caae8ae9e6d30bbbffbc11be5067bc5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"2f7d13d5e2f6973e2a1bd797a14421cb7d9d79d2fd1ec1cbb47834288b668167"} +{"hash_algorithm":"sha256","ts":"2026-10-18T06:39:11.323Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/25","value":{"created_at":"2026-10-18T06:39:11.323Z","author":"codex-agent","text":"Resource-drill stabilization verified physically: the deadline fixture forwards the genuine packaged LM zero-step progress and blocks before fit; the unchanged 15000 ms guard kills it. The separate minimal allocator records its V8 heap ceiling above the unchanged 201326592-byte cgroup cap, then causes a native Docker OOM; the OOMKilled assertion is preserved. Every existing failed/settled/no-completion/one-Run/no-promoted-generation/retained-input/event/container-removal/resume-refusal assertion remains. Focused restored test passes 1/1. In an isolated source snapshot, reverting only memory-worker dispatch fails 0/1 with Missing expected rejection for memory; reverting only the time barrier fails 0/1 with missing time-barrier evidence; restoring both passes 1/1. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. The PM-linked run also passes 1/1, zero skips. Build:test, lint and static publish attestation pass. Full CI must rerun; leave in progress for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:39:11.323Z"}],"before_hash":"3481c36d0d5ca47685b7d688f30808812caae8ae9e6d30bbbffbc11be5067bc5","after_hash":"4c39db89407361b3db5eb1fd84fce6b4604158cbc00ce5670b7dbddeb4f62182","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e2b9c53994775da7fc80226564c33960e8ceb07bfe80fcf89ec3fa16c09721ae"} diff --git a/docs/meta-live-evidence.json b/docs/meta-live-evidence.json index 7d76cb6a..10f83b29 100644 --- a/docs/meta-live-evidence.json +++ b/docs/meta-live-evidence.json @@ -587,5 +587,7 @@ }, "dataset": "a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c" }, - "dataset_build_and_controller_elapsed_ms": 93734.67408900001 + "dataset_build_and_controller_elapsed_ms": 93734.67408900001, + "elapsed_ms": 92238.67339099999, + "source_head": "c882cc2527ace62cff02af25a85b5bb30dedb2a4" } diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 10222d1b..5074d528 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -134,4 +134,4 @@ and reward bounds [0,1]. Each side's Hoeffding half-width is 0.10889390591705964. No recipe was promoted in either generation. The final-test score was **198/385 = 0.5142857142857142 before and after**. No real-data recipe improvement is claimed, and the gate was not relaxed. Dataset build plus controller -execution took 93,734.674089 ms inside the command's unchanged 15-minute watchdog. +execution took 92,238.67339099999 ms inside the command's unchanged 15-minute watchdog. diff --git a/test/fixtures/lm-compose-memory.ts b/test/fixtures/lm-compose-memory.ts new file mode 100644 index 00000000..a37c196a --- /dev/null +++ b/test/fixtures/lm-compose-memory.ts @@ -0,0 +1,14 @@ +/** Exhaust the container's physical memory guard without loading the LM or hitting a smaller V8 heap ceiling first. */ +import { Buffer } from "node:buffer"; +import { appendFileSync, closeSync, fsyncSync, openSync, writeFileSync } from "node:fs"; +import { getHeapStatistics } from "node:v8"; + +appendFileSync("launches.ndjson", `${JSON.stringify({ started: true })}\n`); +process.stdin.resume(); +const handle = openSync("partial.json", "wx"); +try { + writeFileSync(handle, JSON.stringify({ allocation_started: true, heap_limit_bytes: getHeapStatistics().heap_size_limit })); + fsyncSync(handle); +} finally { closeSync(handle); } +const blocks: Buffer[] = []; +for (;;) blocks.push(Buffer.alloc(8 * 1024 * 1024, 1)); diff --git a/test/fixtures/lm-compose-trainer.ts b/test/fixtures/lm-compose-trainer.ts index cab9dc4f..613ac062 100644 --- a/test/fixtures/lm-compose-trainer.ts +++ b/test/fixtures/lm-compose-trainer.ts @@ -1,15 +1,18 @@ -/** Real LM fits plus deterministic corruption, memory exhaustion and mid-fit barriers. */ -import { appendFileSync, writeFileSync } from "node:fs"; +/** Real LM fits with deterministic corruption and an explicit deadline barrier. */ +import { appendFileSync, writeFileSync, writeSync } from "node:fs"; +import { Writable } from "node:stream"; import { runLmTrainer } from "../../process-lm-trainer.ts"; import { writeTrainerArtifact } from "../../process-bandit.ts"; appendFileSync("launches.ndjson", `${JSON.stringify({ started: true })}\n`); const mode = process.env["TRAINER_MODE"]; -if (mode === "memory") { - process.stdin.resume(); - writeTrainerArtifact("partial.json", { allocation_started: true }); - const blocks: Buffer[] = []; - for (;;) blocks.push(Buffer.alloc(8 * 1024 * 1024, 1)); -} else { - await runLmTrainer(); - if (mode === "corrupt") writeFileSync("checkpoint.json", "corrupt"); -} +const stdout = mode === "time" ? new Writable({ + /** Publish the real initial progress event, then hold this fault-injected worker past its unchanged deadline. */ + write(chunk: Buffer, _encoding, callback) { + writeSync(process.stdout.fd, chunk); + writeTrainerArtifact("time-barrier.json", { initial_progress_written: true }); + Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 120_000); + callback(); + }, +}) : process.stdout; +await runLmTrainer(process.stdin, stdout); +if (mode === "corrupt") writeFileSync("checkpoint.json", "corrupt"); diff --git a/test/fixtures/lm-compose.Dockerfile b/test/fixtures/lm-compose.Dockerfile index c2039d84..d3f9de34 100644 --- a/test/fixtures/lm-compose.Dockerfile +++ b/test/fixtures/lm-compose.Dockerfile @@ -5,8 +5,8 @@ COPY package.json package-lock.json ./ RUN npm ci --ignore-scripts --no-audit --no-fund COPY *.ts ./ COPY scripts/script-launcher.ts ./scripts/ -COPY test/fixtures/lm-compose-trainer.ts ./test/fixtures/ +COPY test/fixtures/lm-compose-trainer.ts test/fixtures/lm-compose-memory.ts ./test/fixtures/ ARG MODE=fit ENV TRAINER_MODE=$MODE USER node -ENTRYPOINT ["node", "/trainer/test/fixtures/lm-compose-trainer.ts"] +ENTRYPOINT ["sh", "-c", "if [ \"$TRAINER_MODE\" = memory ]; then exec node --max-old-space-size=1024 /trainer/test/fixtures/lm-compose-memory.ts; fi; exec node /trainer/test/fixtures/lm-compose-trainer.ts"] diff --git a/test/lm-compose.test.ts b/test/lm-compose.test.ts index e748d305..2b37d344 100644 --- a/test/lm-compose.test.ts +++ b/test/lm-compose.test.ts @@ -186,16 +186,26 @@ test("real Compose LM mid-fit cancellation retains evidence and process_cancelle test("real Compose LM corrupt checkpoints and exceeded memory/time refuse promotion", { skip }, async () => { for (const mode of ["corrupt", "memory", "time"]) { const { client, coordinates, approval, pmRoot } = await processWorkspace(budget); - const selected = mode === "time" ? { ...adapter(), allowance: { ...allowance, training_steps: 1000, wall_ms: 15_000, tokens: 1_000_000 } } : mode === "memory" ? { ...adapter(mode), memory_bytes: 201_326_592 } : adapter(mode); + const selected = mode === "time" ? { ...adapter("time"), allowance: { ...allowance, training_steps: 1000, wall_ms: 15_000, tokens: 1_000_000 } } : mode === "memory" ? { ...adapter(mode), memory_bytes: 201_326_592 } : adapter(mode); const cfg = mode === "time" ? { ...rawConfig(selected) as Record, fit_steps: 1000, limits: { ...example["limits"] as Record, max_steps: 2060 } } : rawConfig(selected); - await assert.rejects(runRlLoop(client, coordinates, { id: "process-drill", approval, config: cfg })); + await assert.rejects(runRlLoop(client, coordinates, { id: "process-drill", approval, config: cfg }), Error, `${mode}: the injected resource fault must refuse`); const [job] = await listProcessJobs(client); assert.equal(job.state, "failed"); assert.equal(job.settled, true); assert.equal(job.completion, null); - assert.equal((await client.listAllComplete({})).items.filter((item) => item.type === "Run").length, 1); + assert.equal((await client.listAllComplete({})).items.filter((item) => item.type === "Run").length, 1, `${mode}: a failed fit cannot collect a successor`); assert.equal((await client.listAllComplete({})).items.filter((item) => item.type === "Generation" && item.status === "closed").length, 0); assert.equal(job.outcome, mode === "corrupt" ? "process_checkpoint_invalid" : mode === "time" ? "process_limit_exceeded" : "trainer_failure"); const directory = processStaging(pmRoot, job.id); assert.ok(existsSync(join(directory, "input.json"))); - if (mode === "memory") { assert.ok(existsSync(join(directory, "partial.json"))); assert.equal(JSON.parse(readFileSync(join(directory, "compose-stop.json"), "utf8")).resources.oom_killed, true); } - if (mode === "time") assert.ok(existsSync(join(directory, "events.ndjson"))); + if (mode === "memory") { + assert.ok(existsSync(join(directory, "partial.json"))); + const partial = JSON.parse(readFileSync(join(directory, "partial.json"), "utf8")) as { heap_limit_bytes: number }; + assert.ok(partial.heap_limit_bytes > selected.memory_bytes, "the physical cgroup guard must precede the V8 heap ceiling"); + const stopped = JSON.parse(readFileSync(join(directory, "compose-stop.json"), "utf8")) as { resources: { oom_killed: boolean } }; + assert.equal(stopped.resources.oom_killed, true); + } + if (mode === "time") { + assert.ok(existsSync(join(directory, "events.ndjson"))); + const barrier = JSON.parse(readFileSync(join(directory, "time-barrier.json"), "utf8")) as { initial_progress_written: boolean }; + assert.equal(barrier.initial_progress_written, true); + } removed(job.id, directory); await assert.rejects(resumeRlLoop(client, coordinates, { id: "process-drill", approval })); } From d162a5386b6a504b8c0a686889daeda0cc6e6068 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 09:05:52 +0200 Subject: [PATCH 05/24] docs: record measured meta-recursive acceptance and tracker handoff --- .agents/pm/features/pm-rl-meta.toon | 7 +++---- .agents/pm/features/pm-rl-whrd.toon | 7 +++---- .agents/pm/history/pm-rl-meta.jsonl | 2 ++ .agents/pm/history/pm-rl-whrd.jsonl | 2 ++ RECURSIVE_TRAINING.md | 31 +++++++++++++++++++---------- docs/meta-recursive.md | 30 +++++++++++++++++++++++++++- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 00fdc32f..46c740b1 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T06:39:15.630Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T07:03:21.013Z" author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[17]{created_at,author,text}: +comments[18]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -30,6 +28,7 @@ comments[17]{created_at,author,text}: "2026-10-18T06:03:14.724Z",codex-agent,"Pinned-PM linked verification on the corrected tree passes 9/9 for node --test test/recipe.test.ts test/dataset.test.ts and 1/1 for node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts, zero failures/skips. The existing physical-kill, genuine-promotion and one-approval linked trio previously passed 3/3 and remains in the full suite. Test-result persistence remains disabled by project policy; comments retain the receipts. Build and test compilation, lint, duplicate detection and docstring verification pass: 35 source files, 295 documented declarations, zero clones. The documented approval-template CLI smoke also passes against a real tracker with a full Decision read." "2026-10-18T06:08:25.887Z",codex-agent,"Corrected-source live acceptance PASS on c882cc2527ace62cff02af25a85b5bb30dedb2a4: npm run test:live reproduced the complete real dataset manifest and report exactly. Two meta-generations, K=2, 25 public MIT repositories, 1767 examples (1023 train, 145 inner held-out, 214 meta-validation, 385 final-test). Incumbent b77fdfeff48d; candidates 800886e9f4cd, 45113586500f, 4a48567235f1 and 55539a90ca05 all score 107/214, gain 0, lower gain bound -0.21778781183411927; none promoted. Final-test before/after remains 198/385=0.5142857142857142. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c. Dataset/controller elapsed 92238.67339099999 ms within the unchanged 15-minute watchdog. Source identity is recorded in docs/meta-live-evidence.json. Recipe, bounds, seed, approvals, splits and statistical settings were not tuned after final-test exposure. Current full CI is still running with 612 tests." "2026-10-18T06:39:15.630Z",codex-agent,"The corrected production source c882cc2 passed the full Bun release gate 612/612, zero failures/skips, all 35 required sources at 100/100/100/100 and 295 documented declarations. The Node 22 and Node 26 jobs each failed only the existing Compose LM resource drill, respectively missing native OOM evidence and collecting a second Run. Those fault-injection assumptions are now explicit and bounded, tracked with pm-rl-whrd: native allocator and deadline barrier with unchanged limits/assertions. Both fixture-only behavioural reverts fail 0/1; restored physical and PM-linked checks pass 1/1 each. Linked feature tests now cover 9/9 data/recipe, 3/3 core crash/promotion/budget, 1/1 canonical identity and 1/1 real resource refusal. Production training, recipe bounds, splits and statistical promotion are unchanged. The complete 612-test npm/Bun CI matrix must pass on the forthcoming commit; no passing npm result is claimed for c882cc2." + "2026-10-18T07:03:11.951Z",codex-agent,"Complete verification PASS on 445b2327b4f60a0b7f183e7c6195f7d883b41c53: CI https://github.com/unbraind/pm-rl/actions/runs/39104826277 executes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME and global/system Git configuration. Each passes 612/612, zero failures/skips/cancellations, statements/lines/branches/functions 100/100/100/100 across all 35 required sources, 295 documented declarations, zero clones and production audit findings. Publish attestation, identities, package contents, changelog and Bun graph install pass; CodeQL passes. Fresh PM-linked core run passes 3/3 on the corrected production source, alongside 9/9 data/recipe, 1/1 identity and 1/1 native resource refusal. RECURSIVE_TRAINING.md criterion 7 is Met for bounded execution and honest refusal; live source c882cc2 reproduces all real-data results exactly, with no recipe promoted or final-test gain. Six behavioural revert proofs fail with tests retained, restored implementations pass. External review provides no approval: CodeRabbit skips under its star policy, Greptile trial expired, Sourcery skipped, Cubic neutral. Recorded local HTTP timeout remains failed evidence; no deadline, threshold, dependency pin, telemetry setting or release approval changed. Leave in progress for orchestrator verification; the final receipt commit changes documentation/tracker state only and its exact-head CI will be checked before stopping." files[23]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/features/pm-rl-whrd.toon b/.agents/pm/features/pm-rl-whrd.toon index 68dc53af..fba85ef1 100644 --- a/.agents/pm/features/pm-rl-whrd.toon +++ b/.agents/pm/features/pm-rl-whrd.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags[3]: execution,llm-adapter,recursive-training created_at: "2026-10-15T22:07:13.392Z" -updated_at: "2026-10-18T06:39:11.323Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T07:03:27.069Z" author: codex-agent acceptance_criteria: "Two real generations with successor collection; SIGKILL recovery, cancellation, corrupt checkpoint and limit refusals, one-launch contention; behavioural revert proofs and unchanged npm and Bun release gates." parent: pm-rl-apvf -comments[26]{created_at,author,text}: +comments[27]{created_at,author,text}: "2026-10-15T22:07:43.111Z",codex-agent,"Design: extend the existing process contract with a typed LM payload and checkpoint validator; share owner fences, atomic reservation, staged adoption, cancellation and settlement. Keep held-out examples in the controller. Bind immutable image, memory and CPU ceilings into programme and job identity; send only frozen weights, source adapter, training strings and collected rewards to a networkless non-root container. Add real recursive generations and crash/cancellation/limit/contention drills, then behavioural revert proofs and unchanged release gates." "2026-10-15T22:16:06.750Z",codex-agent,"First real Compose evidence: generation 1 checkpoint 058aa3d2c08438abd18cf0e9b455aca99ddb95492de852201c55c79a0672130d -> 37e503748a170be32e1d506997b6c0cc5c9ee256b24ab01fb49cf0564da07b4c; held-out sampled reward 0.183854, six steps, 1152 target tokens, observed wall 5567 ms, fit CPU 820 ms, peak RSS 138629120 bytes, retained staging 88930 bytes. Generation 2 collected with that promoted digest and trained -> 086f78992283cba37929321abe3961ca6132a52c332bf8a8387a52f22141cbdb; reward 0.292396, six steps, 1152 tokens, wall 5654 ms, CPU 803 ms, peak RSS 143323136 bytes, staging 92364 bytes. Both promoted through the existing gate. Real controller SIGKILL after completion before receipt commit recovered the same checkpoint and original reservation with one launch. Mid-fit cancellation retained input/events and process_cancelled. Full drills and coverage verification continue. The first linked run reached its default 120-second timeout; rerun will explicitly allow the complete integration duration." "2026-10-15T22:24:09.789Z",codex-agent,"Validated linked run: pm test pm-rl-whrd --run --progress --timeout 900 passed 8/8, zero failures/skips/cancellations/todo. Real kernel memory drill retained partial allocation evidence and daemon oom_killed=true at 201326592 bytes; the time drill began the real 1000-step fit before exceeding its 15000 ms allowance. Both refused promotion and successor collection. Two-generation execution took 54134.161 ms; independent verification/replay/status took 4470.981 ms. Canonical hashes and held-out objectives match the first measurement. Final fit resources: generation 1 wall 4297 ms, CPU 713 ms, RSS 138207232 bytes, staging 89057 bytes; generation 2 wall 4266 ms, CPU 759 ms, RSS 144183296 bytes, staging 92509 bytes; both six steps and 1152 target tokens. Daemon receipts verify memory=268435456, CPU=1, no network and non-root user. Existing Compose barrier variability is tracked in pm-rl-8nev. Revert proofs and complete release gates remain in progress." @@ -39,6 +37,7 @@ comments[26]{created_at,author,text}: "2026-10-18T03:01:05.676Z",codex-agent,"Audit: MET against recorded acceptance. Merged PR #80 (b255dfac6543ab178ab2720fad1de1ba49f91dd4) supplies two real external LM generations and successor collection, SIGKILL staged-completion recovery without retraining or double charge, cancellation, corrupt checkpoint and resource refusals, and one-launch contention. docs/lm-adapter.md and test/lm-compose.test.ts retain measured evidence; feature and fixture behavioural revert proofs are recorded. Final isolated npm and Bun release gates each passed 590/590 with exact four-metric 100% coverage. No acceptance gap found in merged evidence; storage kernel enforcement remains separately tracked in pm-rl-7073. Leave open for orchestrator verification." "2026-10-18T06:19:59.564Z",codex-agent,"Current meta-feature CI exposed a timing-dependent existing fault drill: the Node 26 job observed two collection Runs instead of one in the corrupt/memory/time test, while every authored source reported 100% lines/branches/functions. The time case assumed 1000 real LM fit steps necessarily exceeded 15000 ms; that assumption depends on runner speed. The correction selects a time-only fixture that enters the actual packaged LM trainer, publishes its genuine zero-step progress, retains a barrier marker and blocks before numerical fit until the unchanged process deadline terminates the container. Corrupt and memory modes, the 15000 ms allowance, every existing failure/no-successor/cleanup/resume assertion, production training and promotion criteria remain unchanged. Focused physical verification and full gates are pending. The earlier merged acceptance audit remains historical evidence, not a passing result for this new attempt." "2026-10-18T06:39:11.323Z",codex-agent,"Resource-drill stabilization verified physically: the deadline fixture forwards the genuine packaged LM zero-step progress and blocks before fit; the unchanged 15000 ms guard kills it. The separate minimal allocator records its V8 heap ceiling above the unchanged 201326592-byte cgroup cap, then causes a native Docker OOM; the OOMKilled assertion is preserved. Every existing failed/settled/no-completion/one-Run/no-promoted-generation/retained-input/event/container-removal/resume-refusal assertion remains. Focused restored test passes 1/1. In an isolated source snapshot, reverting only memory-worker dispatch fails 0/1 with Missing expected rejection for memory; reverting only the time barrier fails 0/1 with missing time-barrier evidence; restoring both passes 1/1. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. The PM-linked run also passes 1/1, zero skips. Build:test, lint and static publish attestation pass. Full CI must rerun; leave in progress for orchestrator verification." + "2026-10-18T07:03:16.944Z",codex-agent,"Final current validation: CI run https://github.com/unbraind/pm-rl/actions/runs/39104826277 on 445b232 passes all three complete gates (npm Node 22, npm Node 26, Bun Node 26), 612/612 each, zero skips, all four coverage metrics 100% across 35 required sources and 295 documented declarations. The real corruption/native-OOM/15-second-deadline refusal drill passes with every original failure, no-successor, cleanup and resume assertion retained. Its two fault-guard reverts fail 0/1 each; restored physical and linked verification passes 1/1. The original merged-PR acceptance audit remains Met, now supplemented by stable current fault injection. No production trainer or promotion changes, pin bump, larger physical allowance or release enablement. Leave in progress for orchestrator closure; release the claim after these receipts." files[21]{path,scope}: .dockerignore,project compose.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index b8b9e38a..e4a2161c 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -34,3 +34,5 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T06:35:11.981Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/20/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/19/path","value":"test/lm-compose.test.ts"},{"op":"replace","path":"/metadata/files/18/path","value":"test/fixtures/tracker-histories.json"},{"op":"replace","path":"/metadata/files/17/path","value":"test/fixtures/meta-workspace.ts"},{"op":"replace","path":"/metadata/files/16/path","value":"test/fixtures/meta-controller.ts"},{"op":"replace","path":"/metadata/files/15/path","value":"test/fixtures/lm-compose.Dockerfile"},{"op":"replace","path":"/metadata/files/14/path","value":"test/fixtures/lm-compose-trainer.ts"},{"op":"replace","path":"/metadata/files/13/path","value":"test/fixtures/lm-compose-memory.ts"},{"op":"add","path":"/metadata/files/21","value":{"path":"test/recipe.test.ts","scope":"project"}},{"op":"add","path":"/metadata/files/22","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:35:11.981Z"}],"before_hash":"f7a706fbae7bac81bfb8394034a2a11cd2e0214a6e1527fd6401e389ca822b59","after_hash":"d7de1c581ed048c7e09e4f34408ed947daede7ff991270e8b58560ee432d4af9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"87e54a7ffebf1fe4c07ed1f14ac0dfc67d4507b873f53098f33246104c1f856e"} {"hash_algorithm":"sha256","ts":"2026-10-18T06:35:19.054Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/3","value":{"command":"node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T06:35:18.894Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:35:19.054Z"}],"before_hash":"d7de1c581ed048c7e09e4f34408ed947daede7ff991270e8b58560ee432d4af9","after_hash":"01e08f20abee94cab6d5086614cb4d622988cd61fd8f763efb4c49aeac775f34","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"46491d3dafb1e80d0ee13051842dd2b5299409eeb8a6244fe2cf865d2d2c89dc"} {"hash_algorithm":"sha256","ts":"2026-10-18T06:39:15.630Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/16","value":{"created_at":"2026-10-18T06:39:15.630Z","author":"codex-agent","text":"The corrected production source c882cc2 passed the full Bun release gate 612/612, zero failures/skips, all 35 required sources at 100/100/100/100 and 295 documented declarations. The Node 22 and Node 26 jobs each failed only the existing Compose LM resource drill, respectively missing native OOM evidence and collecting a second Run. Those fault-injection assumptions are now explicit and bounded, tracked with pm-rl-whrd: native allocator and deadline barrier with unchanged limits/assertions. Both fixture-only behavioural reverts fail 0/1; restored physical and PM-linked checks pass 1/1 each. Linked feature tests now cover 9/9 data/recipe, 3/3 core crash/promotion/budget, 1/1 canonical identity and 1/1 real resource refusal. Production training, recipe bounds, splits and statistical promotion are unchanged. The complete 612-test npm/Bun CI matrix must pass on the forthcoming commit; no passing npm result is claimed for c882cc2."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:39:15.630Z"}],"before_hash":"01e08f20abee94cab6d5086614cb4d622988cd61fd8f763efb4c49aeac775f34","after_hash":"4ba5019dd7d496c47ed2b7c33cd01ee1a5aec666575fc5f786c8f642d1adbec4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"57203ad1335d8b29fbdd0ddfe6ff00c2c8d73d3b5afd02f087c8d34ade94f892"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:03:11.951Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/17","value":{"created_at":"2026-10-18T07:03:11.951Z","author":"codex-agent","text":"Complete verification PASS on 445b2327b4f60a0b7f183e7c6195f7d883b41c53: CI https://github.com/unbraind/pm-rl/actions/runs/39104826277 executes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME and global/system Git configuration. Each passes 612/612, zero failures/skips/cancellations, statements/lines/branches/functions 100/100/100/100 across all 35 required sources, 295 documented declarations, zero clones and production audit findings. Publish attestation, identities, package contents, changelog and Bun graph install pass; CodeQL passes. Fresh PM-linked core run passes 3/3 on the corrected production source, alongside 9/9 data/recipe, 1/1 identity and 1/1 native resource refusal. RECURSIVE_TRAINING.md criterion 7 is Met for bounded execution and honest refusal; live source c882cc2 reproduces all real-data results exactly, with no recipe promoted or final-test gain. Six behavioural revert proofs fail with tests retained, restored implementations pass. External review provides no approval: CodeRabbit skips under its star policy, Greptile trial expired, Sourcery skipped, Cubic neutral. Recorded local HTTP timeout remains failed evidence; no deadline, threshold, dependency pin, telemetry setting or release approval changed. Leave in progress for orchestrator verification; the final receipt commit changes documentation/tracker state only and its exact-head CI will be checked before stopping."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:03:11.951Z"}],"before_hash":"4ba5019dd7d496c47ed2b7c33cd01ee1a5aec666575fc5f786c8f642d1adbec4","after_hash":"d7ac282e5a28f9c239c3be1eeb3a5fd16c83c1022a7b0c0f43e6a96b2cdb5aae","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"80295e05b039b3931b2d39909de8540876e7d1311b1e1309070f1c89c4c6cfc1"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:03:21.013Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:03:21.013Z"}],"before_hash":"d7ac282e5a28f9c239c3be1eeb3a5fd16c83c1022a7b0c0f43e6a96b2cdb5aae","after_hash":"07daeeb1b5ccd2a086ca9061eb8b2012ad1a9c6cefd2221a0586087b94a514cc","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"f50dfc93b0d0aee6a0133cd7decffa9eefbb81645d5cd2775f1399d1fe63753b"} diff --git a/.agents/pm/history/pm-rl-whrd.jsonl b/.agents/pm/history/pm-rl-whrd.jsonl index f84fa642..fc0dac4a 100644 --- a/.agents/pm/history/pm-rl-whrd.jsonl +++ b/.agents/pm/history/pm-rl-whrd.jsonl @@ -46,3 +46,5 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T06:19:59.564Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/24","value":{"created_at":"2026-10-18T06:19:59.564Z","author":"codex-agent","text":"Current meta-feature CI exposed a timing-dependent existing fault drill: the Node 26 job observed two collection Runs instead of one in the corrupt/memory/time test, while every authored source reported 100% lines/branches/functions. The time case assumed 1000 real LM fit steps necessarily exceeded 15000 ms; that assumption depends on runner speed. The correction selects a time-only fixture that enters the actual packaged LM trainer, publishes its genuine zero-step progress, retains a barrier marker and blocks before numerical fit until the unchanged process deadline terminates the container. Corrupt and memory modes, the 15000 ms allowance, every existing failure/no-successor/cleanup/resume assertion, production training and promotion criteria remain unchanged. Focused physical verification and full gates are pending. The earlier merged acceptance audit remains historical evidence, not a passing result for this new attempt."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:19:59.564Z"}],"before_hash":"0a669565cd9ddf815ae74ecdff1aa1a55224554f3f4af5c95812c02d4d0e89bb","after_hash":"63f05069e58977aa2015ff40818bce5a4858d51411a6efd1b9ec77cf75a72956","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2abc2a1d39241bc710e3b1f5d86b43b9997f4cefb1c0bacefe05604e0a4955d9"} {"hash_algorithm":"sha256","ts":"2026-10-18T06:35:15.670Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/19/path","value":"test/fixtures/process-controller.ts"},{"op":"replace","path":"/metadata/files/18/path","value":"test/fixtures/lm-compose.Dockerfile"},{"op":"replace","path":"/metadata/files/17/path","value":"test/fixtures/lm-compose-trainer.ts"},{"op":"replace","path":"/metadata/files/16/path","value":"test/fixtures/lm-compose-memory.ts"},{"op":"add","path":"/metadata/files/20","value":{"path":"test/lm-compose.test.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:35:15.670Z"}],"before_hash":"63f05069e58977aa2015ff40818bce5a4858d51411a6efd1b9ec77cf75a72956","after_hash":"3481c36d0d5ca47685b7d688f30808812caae8ae9e6d30bbbffbc11be5067bc5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"2f7d13d5e2f6973e2a1bd797a14421cb7d9d79d2fd1ec1cbb47834288b668167"} {"hash_algorithm":"sha256","ts":"2026-10-18T06:39:11.323Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/25","value":{"created_at":"2026-10-18T06:39:11.323Z","author":"codex-agent","text":"Resource-drill stabilization verified physically: the deadline fixture forwards the genuine packaged LM zero-step progress and blocks before fit; the unchanged 15000 ms guard kills it. The separate minimal allocator records its V8 heap ceiling above the unchanged 201326592-byte cgroup cap, then causes a native Docker OOM; the OOMKilled assertion is preserved. Every existing failed/settled/no-completion/one-Run/no-promoted-generation/retained-input/event/container-removal/resume-refusal assertion remains. Focused restored test passes 1/1. In an isolated source snapshot, reverting only memory-worker dispatch fails 0/1 with Missing expected rejection for memory; reverting only the time barrier fails 0/1 with missing time-barrier evidence; restoring both passes 1/1. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. The PM-linked run also passes 1/1, zero skips. Build:test, lint and static publish attestation pass. Full CI must rerun; leave in progress for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:39:11.323Z"}],"before_hash":"3481c36d0d5ca47685b7d688f30808812caae8ae9e6d30bbbffbc11be5067bc5","after_hash":"4c39db89407361b3db5eb1fd84fce6b4604158cbc00ce5670b7dbddeb4f62182","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e2b9c53994775da7fc80226564c33960e8ceb07bfe80fcf89ec3fa16c09721ae"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:03:16.946Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/26","value":{"created_at":"2026-10-18T07:03:16.944Z","author":"codex-agent","text":"Final current validation: CI run https://github.com/unbraind/pm-rl/actions/runs/39104826277 on 445b232 passes all three complete gates (npm Node 22, npm Node 26, Bun Node 26), 612/612 each, zero skips, all four coverage metrics 100% across 35 required sources and 295 documented declarations. The real corruption/native-OOM/15-second-deadline refusal drill passes with every original failure, no-successor, cleanup and resume assertion retained. Its two fault-guard reverts fail 0/1 each; restored physical and linked verification passes 1/1. The original merged-PR acceptance audit remains Met, now supplemented by stable current fault injection. No production trainer or promotion changes, pin bump, larger physical allowance or release enablement. Leave in progress for orchestrator closure; release the claim after these receipts."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:03:16.946Z"}],"before_hash":"4c39db89407361b3db5eb1fd84fce6b4604158cbc00ce5670b7dbddeb4f62182","after_hash":"8cfda477df504679c0dd958ba96bfed41e962194acdd920dfbdf85203b1ba184","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"741d24fdbeb6bbea9f85fddc07b5733e9b260321e013d48f69f3a871b4b56155"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:03:27.069Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:03:27.069Z"}],"before_hash":"8cfda477df504679c0dd958ba96bfed41e962194acdd920dfbdf85203b1ba184","after_hash":"deb12c248bf96d088c72596e030874315cf497d5872f92235db7072d8f41f6b0","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"509ac1b633cef7411b2f2d08fd891597578298f06e1bf728a166406a5457b00f"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 501fef5a..0b1b7c61 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -63,16 +63,27 @@ Adapters report structured progress and completion evidence over a documented st 4. **Met for local process and Compose adapters:** real SIGKILL after staged completion and before its receipt commit recovers without retraining or double charge; planning/evaluation/promotion crashes and mid-fit SIGTERM retain evidence. Crash and cancellation drills cover every transition, including a complete checkpoint without a committed receipt. Restart is idempotent and does not overwrite prior artifacts. 5. **Met for local process and Compose adapters:** dataset overlap, reward/environment drift, excessive gap, missing/corrupt receipts, invalid checkpoints and exceeded resource allowances refuse progression; failed candidates never collect the next generation. Contamination, a training-to-evaluation gap above `maximum_gap`, stale reward or environment identity, corrupt checkpoints, missing metrics and exceeded resource limits prevent promotion. A failed candidate cannot become the next collection policy. 6. Unit, real-process integration, CLI acceptance, replay, performance and failure-path tests cover every authored source file at exact statement/line/branch/function thresholds. The docstring gate covers the declared source surface, and the scope inventory names anything it excludes. -7. **Meta-recursive recipe improvement:** `pm rl meta run` names and evolves a - content-addressed bounded recipe, executes bounded inner loops under one - pre-approved Decision with atomic reservations, and promotes recipes only - through the existing statistical gate on repository-isolated meta-validation - evidence. Inner held-out examples are confined to their evaluator; final-test - repositories are opened only after selection. Real public MIT tracker histories - carry source repository and commit identity. The builder excludes hosted data, - pm-web and pm-gpt. [The contract and live evidence](docs/meta-recursive.md) and - [pm-rl-meta](.agents/pm/features/pm-rl-meta.toon) track this criterion; its - real-data and full-gate acceptance is pending until measured below. +7. **Met: Meta-recursive recipe improvement.** `pm rl meta run` names and evolves + a content-addressed bounded recipe, records its digest in every inner + generation, and executes bounded inner loops under one pre-approved Decision + with atomic reservations. Recipe promotion uses the existing statistical gate + on repository-isolated meta-validation evidence. Inner held-out examples stay + in their evaluator; final-test repositories are opened after selection. Public + MIT histories retain repository and commit provenance; hosted data, pm-web and + pm-gpt are excluded. [The contract](docs/meta-recursive.md), + [public live evidence](docs/meta-live-evidence.json) and + [pm-rl-meta](.agents/pm/features/pm-rl-meta.toon) retain the implementation and + receipts. Live acceptance on the corrected source executes two meta-generations + with two candidates each over 25 repositories and 1,767 examples. All four + candidates score 107/214, gain 0, lower gain bound -0.21778781183411927; none + promotes. Final-test before/after is 198/385. No real-data improvement is claimed. + [Complete release verification](https://github.com/unbraind/pm-rl/actions/runs/39104826277) + passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: + 612/612 each, zero failures/skips, all four coverage metrics 100% across all + 35 declared sources and 295 documented declarations. Physical crash, shared + budget, conditional promotion and resource-refusal regressions pass; six + behaviour-only reverts fail with tests retained and restored code passes. + ## Data boundary and capacity diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 5074d528..c0d0015e 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -134,4 +134,32 @@ and reward bounds [0,1]. Each side's Hoeffding half-width is 0.10889390591705964. No recipe was promoted in either generation. The final-test score was **198/385 = 0.5142857142857142 before and after**. No real-data recipe improvement is claimed, and the gate was not relaxed. Dataset build plus controller -execution took 92,238.67339099999 ms inside the command's unchanged 15-minute watchdog. +execution took 92,238.673391 ms inside the command's unchanged 15-minute watchdog. + + +## Release verification + +The [complete CI run](https://github.com/unbraind/pm-rl/actions/runs/39104826277) +executes `npm run release:check` on Node 22 and 26 and `bun run release:check` on +Node 26 with isolated HOME and global/system Git configuration. Each passes +612/612 tests, zero failures/skips, 100% statements/lines/branches/functions over +all 35 declared sources, 295 documented declarations, and zero duplicate clones +or production audit findings. Thresholds, dependency pins and release approval +are unchanged. The live evidence names the measured production source commit; +the later resource-fixture changes affect acceptance tests only. + +The real Compose resource faults are explicit: the deadline worker publishes +real LM progress then pauses past its unchanged 15-second limit; the memory +worker has a V8 ceiling above its unchanged 192 MiB physical cgroup cap and is +actually OOM-killed. Existing no-successor, receipt, cleanup and resume assertions +remain. Guard-only reverts for recipe lineage, public visibility, programme ids, +retained reservation case folding and both resource fault injectors fail; restored +implementations pass. PM-linked data/recipe, crash/promotion/budget, identity and +resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. + +A separate local full-suite attempt hit the unchanged 300-second HTTP crash-drill +deadline under host load and was retained as failed evidence. The required complete +commands pass in CI. External review is incomplete: CodeRabbit skips automatic +review under its star policy, Greptile reports an expired trial, Sourcery skips +and Cubic is neutral. Those states provide no approval. The PR remains unmerged, +work items remain in progress, and the orchestrator owns closure. From a2d9461e0c475cd210cd572481d71154e1a7f2f8 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 09:14:55 +0200 Subject: [PATCH 06/24] style: trim evaluator end-of-file whitespace --- .agents/pm/features/pm-rl-meta.toon | 5 +++-- .agents/pm/history/pm-rl-meta.jsonl | 3 +++ tracker-environment.ts | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 46c740b1..29060eb9 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,11 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T07:03:21.013Z" +updated_at: "2026-10-18T07:14:46.977Z" author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[18]{created_at,author,text}: +comments[19]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -29,6 +29,7 @@ comments[18]{created_at,author,text}: "2026-10-18T06:08:25.887Z",codex-agent,"Corrected-source live acceptance PASS on c882cc2527ace62cff02af25a85b5bb30dedb2a4: npm run test:live reproduced the complete real dataset manifest and report exactly. Two meta-generations, K=2, 25 public MIT repositories, 1767 examples (1023 train, 145 inner held-out, 214 meta-validation, 385 final-test). Incumbent b77fdfeff48d; candidates 800886e9f4cd, 45113586500f, 4a48567235f1 and 55539a90ca05 all score 107/214, gain 0, lower gain bound -0.21778781183411927; none promoted. Final-test before/after remains 198/385=0.5142857142857142. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c. Dataset/controller elapsed 92238.67339099999 ms within the unchanged 15-minute watchdog. Source identity is recorded in docs/meta-live-evidence.json. Recipe, bounds, seed, approvals, splits and statistical settings were not tuned after final-test exposure. Current full CI is still running with 612 tests." "2026-10-18T06:39:15.630Z",codex-agent,"The corrected production source c882cc2 passed the full Bun release gate 612/612, zero failures/skips, all 35 required sources at 100/100/100/100 and 295 documented declarations. The Node 22 and Node 26 jobs each failed only the existing Compose LM resource drill, respectively missing native OOM evidence and collecting a second Run. Those fault-injection assumptions are now explicit and bounded, tracked with pm-rl-whrd: native allocator and deadline barrier with unchanged limits/assertions. Both fixture-only behavioural reverts fail 0/1; restored physical and PM-linked checks pass 1/1 each. Linked feature tests now cover 9/9 data/recipe, 3/3 core crash/promotion/budget, 1/1 canonical identity and 1/1 real resource refusal. Production training, recipe bounds, splits and statistical promotion are unchanged. The complete 612-test npm/Bun CI matrix must pass on the forthcoming commit; no passing npm result is claimed for c882cc2." "2026-10-18T07:03:11.951Z",codex-agent,"Complete verification PASS on 445b2327b4f60a0b7f183e7c6195f7d883b41c53: CI https://github.com/unbraind/pm-rl/actions/runs/39104826277 executes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME and global/system Git configuration. Each passes 612/612, zero failures/skips/cancellations, statements/lines/branches/functions 100/100/100/100 across all 35 required sources, 295 documented declarations, zero clones and production audit findings. Publish attestation, identities, package contents, changelog and Bun graph install pass; CodeQL passes. Fresh PM-linked core run passes 3/3 on the corrected production source, alongside 9/9 data/recipe, 1/1 identity and 1/1 native resource refusal. RECURSIVE_TRAINING.md criterion 7 is Met for bounded execution and honest refusal; live source c882cc2 reproduces all real-data results exactly, with no recipe promoted or final-test gain. Six behavioural revert proofs fail with tests retained, restored implementations pass. External review provides no approval: CodeRabbit skips under its star policy, Greptile trial expired, Sourcery skipped, Cubic neutral. Recorded local HTTP timeout remains failed evidence; no deadline, threshold, dependency pin, telemetry setting or release approval changed. Leave in progress for orchestrator verification; the final receipt commit changes documentation/tracker state only and its exact-head CI will be checked before stopping." + "2026-10-18T07:14:44.751Z",codex-agent,"Final full-branch whitespace verification found one extra blank line at the end of tracker-environment.ts. Removed only that blank line; runtime statements, knobs, data and promotion criteria are unchanged. The full diff whitespace check now passes. The prior complete code gate remains 612/612 in all three CI variants; the formatting head will receive the same exact-command matrix before stopping. Release the claim after this formatting-only handoff; leave status in progress and closure to the orchestrator." files[23]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index e4a2161c..3ee9eded 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -36,3 +36,6 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T06:39:15.630Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/16","value":{"created_at":"2026-10-18T06:39:15.630Z","author":"codex-agent","text":"The corrected production source c882cc2 passed the full Bun release gate 612/612, zero failures/skips, all 35 required sources at 100/100/100/100 and 295 documented declarations. The Node 22 and Node 26 jobs each failed only the existing Compose LM resource drill, respectively missing native OOM evidence and collecting a second Run. Those fault-injection assumptions are now explicit and bounded, tracked with pm-rl-whrd: native allocator and deadline barrier with unchanged limits/assertions. Both fixture-only behavioural reverts fail 0/1; restored physical and PM-linked checks pass 1/1 each. Linked feature tests now cover 9/9 data/recipe, 3/3 core crash/promotion/budget, 1/1 canonical identity and 1/1 real resource refusal. Production training, recipe bounds, splits and statistical promotion are unchanged. The complete 612-test npm/Bun CI matrix must pass on the forthcoming commit; no passing npm result is claimed for c882cc2."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:39:15.630Z"}],"before_hash":"01e08f20abee94cab6d5086614cb4d622988cd61fd8f763efb4c49aeac775f34","after_hash":"4ba5019dd7d496c47ed2b7c33cd01ee1a5aec666575fc5f786c8f642d1adbec4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"57203ad1335d8b29fbdd0ddfe6ff00c2c8d73d3b5afd02f087c8d34ade94f892"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:03:11.951Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/17","value":{"created_at":"2026-10-18T07:03:11.951Z","author":"codex-agent","text":"Complete verification PASS on 445b2327b4f60a0b7f183e7c6195f7d883b41c53: CI https://github.com/unbraind/pm-rl/actions/runs/39104826277 executes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME and global/system Git configuration. Each passes 612/612, zero failures/skips/cancellations, statements/lines/branches/functions 100/100/100/100 across all 35 required sources, 295 documented declarations, zero clones and production audit findings. Publish attestation, identities, package contents, changelog and Bun graph install pass; CodeQL passes. Fresh PM-linked core run passes 3/3 on the corrected production source, alongside 9/9 data/recipe, 1/1 identity and 1/1 native resource refusal. RECURSIVE_TRAINING.md criterion 7 is Met for bounded execution and honest refusal; live source c882cc2 reproduces all real-data results exactly, with no recipe promoted or final-test gain. Six behavioural revert proofs fail with tests retained, restored implementations pass. External review provides no approval: CodeRabbit skips under its star policy, Greptile trial expired, Sourcery skipped, Cubic neutral. Recorded local HTTP timeout remains failed evidence; no deadline, threshold, dependency pin, telemetry setting or release approval changed. Leave in progress for orchestrator verification; the final receipt commit changes documentation/tracker state only and its exact-head CI will be checked before stopping."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:03:11.951Z"}],"before_hash":"4ba5019dd7d496c47ed2b7c33cd01ee1a5aec666575fc5f786c8f642d1adbec4","after_hash":"d7ac282e5a28f9c239c3be1eeb3a5fd16c83c1022a7b0c0f43e6a96b2cdb5aae","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"80295e05b039b3931b2d39909de8540876e7d1311b1e1309070f1c89c4c6cfc1"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:03:21.013Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:03:21.013Z"}],"before_hash":"d7ac282e5a28f9c239c3be1eeb3a5fd16c83c1022a7b0c0f43e6a96b2cdb5aae","after_hash":"07daeeb1b5ccd2a086ca9061eb8b2012ad1a9c6cefd2221a0586087b94a514cc","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"f50dfc93b0d0aee6a0133cd7decffa9eefbb81645d5cd2775f1399d1fe63753b"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:14:41.805Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:14:41.805Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"07daeeb1b5ccd2a086ca9061eb8b2012ad1a9c6cefd2221a0586087b94a514cc","after_hash":"efc58c462a97a675cc90c7690b2dbf4f2074f7df2e207d1cdefa016bbc28957a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7a851079b345556ece2207da535a42ef13ac3fb3cb2e7979841d7bf2f9c070e7"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:14:44.751Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/18","value":{"created_at":"2026-10-18T07:14:44.751Z","author":"codex-agent","text":"Final full-branch whitespace verification found one extra blank line at the end of tracker-environment.ts. Removed only that blank line; runtime statements, knobs, data and promotion criteria are unchanged. The full diff whitespace check now passes. The prior complete code gate remains 612/612 in all three CI variants; the formatting head will receive the same exact-command matrix before stopping. Release the claim after this formatting-only handoff; leave status in progress and closure to the orchestrator."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:14:44.751Z"}],"before_hash":"efc58c462a97a675cc90c7690b2dbf4f2074f7df2e207d1cdefa016bbc28957a","after_hash":"c24cbf775107d7699b546fa0026bd40157ead82075edbb247a85da1dd4998fcd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a4930d68341eba30eb9a778a258d666a91532404c58b2d7ac858ff177b9ead8d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:14:46.977Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:14:46.977Z"}],"before_hash":"c24cbf775107d7699b546fa0026bd40157ead82075edbb247a85da1dd4998fcd","after_hash":"3c707eca73ec01c1f2f3c35b7643784a67c975d91ad3e215d2ab54469ab0112a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"c9d83cfea4b5361faaae482774b7105063c37817d20d9f6344301c18ba18db98"} diff --git a/tracker-environment.ts b/tracker-environment.ts index 8e2c29a4..1710a2d3 100644 --- a/tracker-environment.ts +++ b/tracker-environment.ts @@ -95,4 +95,3 @@ async function fitRecipe(client: PmClient, coordinates: ProcessCoordinates, requ assert.equal(banditCheckpoint(weight).digest, report.final_checkpoint, "meta_checkpoint_identity"); return { recipe, weight, checkpoint: report.final_checkpoint }; } - From 5a142fc38a2591eb464ce63819f32f7101c2a9ef Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 09:48:31 +0200 Subject: [PATCH 07/24] feat: explain recipe sensitivity with baselines and learnable signal --- .agents/pm/features/pm-rl-meta.toon | 19 +- .agents/pm/features/pm-rl-prefix.toon | 17 + .agents/pm/history/pm-rl-meta.jsonl | 8 + .agents/pm/history/pm-rl-prefix.jsonl | 3 + README.md | 5 +- RECURSIVE_TRAINING.md | 11 +- docs/meta-recursive.md | 36 +++ docs/meta-sanity-evidence.json | 247 +++++++++++++++ meta.ts | 20 +- test/fixtures/tracker-signal.json | 430 ++++++++++++++++++++++++++ test/meta.test.ts | 69 ++++- tracker-environment.ts | 47 ++- 12 files changed, 872 insertions(+), 40 deletions(-) create mode 100644 .agents/pm/features/pm-rl-prefix.toon create mode 100644 .agents/pm/history/pm-rl-prefix.jsonl create mode 100644 docs/meta-sanity-evidence.json create mode 100644 test/fixtures/tracker-signal.json diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 29060eb9..f03835e1 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,11 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T07:14:46.977Z" +updated_at: "2026-10-18T07:48:03.342Z" +assignee: codex-agent +claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[19]{created_at,author,text}: +comments[23]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -30,7 +32,11 @@ comments[19]{created_at,author,text}: "2026-10-18T06:39:15.630Z",codex-agent,"The corrected production source c882cc2 passed the full Bun release gate 612/612, zero failures/skips, all 35 required sources at 100/100/100/100 and 295 documented declarations. The Node 22 and Node 26 jobs each failed only the existing Compose LM resource drill, respectively missing native OOM evidence and collecting a second Run. Those fault-injection assumptions are now explicit and bounded, tracked with pm-rl-whrd: native allocator and deadline barrier with unchanged limits/assertions. Both fixture-only behavioural reverts fail 0/1; restored physical and PM-linked checks pass 1/1 each. Linked feature tests now cover 9/9 data/recipe, 3/3 core crash/promotion/budget, 1/1 canonical identity and 1/1 real resource refusal. Production training, recipe bounds, splits and statistical promotion are unchanged. The complete 612-test npm/Bun CI matrix must pass on the forthcoming commit; no passing npm result is claimed for c882cc2." "2026-10-18T07:03:11.951Z",codex-agent,"Complete verification PASS on 445b2327b4f60a0b7f183e7c6195f7d883b41c53: CI https://github.com/unbraind/pm-rl/actions/runs/39104826277 executes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME and global/system Git configuration. Each passes 612/612, zero failures/skips/cancellations, statements/lines/branches/functions 100/100/100/100 across all 35 required sources, 295 documented declarations, zero clones and production audit findings. Publish attestation, identities, package contents, changelog and Bun graph install pass; CodeQL passes. Fresh PM-linked core run passes 3/3 on the corrected production source, alongside 9/9 data/recipe, 1/1 identity and 1/1 native resource refusal. RECURSIVE_TRAINING.md criterion 7 is Met for bounded execution and honest refusal; live source c882cc2 reproduces all real-data results exactly, with no recipe promoted or final-test gain. Six behavioural revert proofs fail with tests retained, restored implementations pass. External review provides no approval: CodeRabbit skips under its star policy, Greptile trial expired, Sourcery skipped, Cubic neutral. Recorded local HTTP timeout remains failed evidence; no deadline, threshold, dependency pin, telemetry setting or release approval changed. Leave in progress for orchestrator verification; the final receipt commit changes documentation/tracker state only and its exact-head CI will be checked before stopping." "2026-10-18T07:14:44.751Z",codex-agent,"Final full-branch whitespace verification found one extra blank line at the end of tracker-environment.ts. Removed only that blank line; runtime statements, knobs, data and promotion criteria are unchanged. The full diff whitespace check now passes. The prior complete code gate remains 612/612 in all three CI variants; the formatting head will receive the same exact-command matrix before stopping. Release the claim after this formatting-only handoff; leave status in progress and closure to the orchestrator." -files[23]{path,scope}: + "2026-10-18T07:41:06.103Z",codex-agent,"Reopened implementation work for PR 84 orchestrator review: measure held-out majority baselines and aggregate prediction diversity, add a committed learnable-signal promotion sanity case at the unchanged live gate, and document a prefix-aware learner follow-up if real-data performance remains below baseline. Existing audits, CI evidence, and completed implementation are retained." + "2026-10-18T07:46:49.973Z",codex-agent,"Review diagnosis on the retained live dataset: majority completed baseline is 211/214 on meta-validation and 384/385 on final-test, versus learner 107/214 and 198/385. All accepted weights are zero because no inner candidate passed promotion; recipes therefore share the same seed policy, rather than collapsing to a single predicted label. Prefix-aware learning is tracked in pm-rl-prefix. Committed tracker-signal fixture uses a declared known signal and the unchanged live criterion confidence 0.95, minimum 10, effect 0.01: generation 1 promotes with gain 0.0686, lower bound 0.03899585625398397; final score rises 5093/10000 to 5806/10000. No real-data threshold or feature changed." + "2026-10-18T07:46:51.026Z",codex-agent,"Behavior-only review revert proofs: restoring only openTrackerEnvironment to its pre-review implementation makes the synthetic majority/diversity regression fail 0/1 (missing diagnostics). Disabling only recipeSuccessor promotion makes the committed learnable-signal test fail 0/1 at its promotion assertion. Both source functions were restored; tests and fixture were retained. Full restored linked run follows." + "2026-10-18T07:48:03.342Z",codex-agent,"Restored linked PM review run passed 2/2 with zero failures, cancellations or skips. Synthetic majority/diversity checks and the committed learnable-signal outer-loop promotion both pass. Aggregate prediction diagnostics do not expose held-out examples or prediction vectors. The retained real snapshot predicts 108 completed and 106 cancelled on meta-validation, 199 completed and 186 cancelled on final-test; candidate disagreement is zero because all accepted checkpoints are the seed." +files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project examples/meta-approval.md,project @@ -50,19 +56,22 @@ files[23]{path,scope}: test/fixtures/meta-controller.ts,project test/fixtures/meta-workspace.ts,project test/fixtures/tracker-histories.json,project + test/fixtures/tracker-signal.json,project test/lm-compose.test.ts,project test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[4]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[5]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts",project,600,codex-agent,"2026-10-18T06:35:18.894Z",local_mutation,feat/meta-recursive-recipe-loop -docs[6]{path,scope}: + "node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T07:43:42.817Z",local_mutation,feat/meta-recursive-recipe-loop +docs[7]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project docs/meta-recursive.md,project + docs/meta-sanity-evidence.json,project examples/meta-approval.md,project README.md,project RECURSIVE_TRAINING.md,project diff --git a/.agents/pm/features/pm-rl-prefix.toon b/.agents/pm/features/pm-rl-prefix.toon new file mode 100644 index 00000000..aa648f94 --- /dev/null +++ b/.agents/pm/features/pm-rl-prefix.toon @@ -0,0 +1,17 @@ +id: pm-rl-prefix +title: Train a history-prefix learner on the public tracker environment +description: "PR 84 acceptance scored 107/214 on meta-validation versus the completed-majority baseline 211/214, and 198/385 on final-test versus 384/385. All candidates retained the zero-weight seed checkpoint because inner fits were refused. Add a bounded learner that actually reads the normalized history prefix, such as the existing LM adapter, on the sealed repository-split tracker environment." +type: Feature +status: open +priority: 2 +tags: [] +created_at: "2026-10-18T07:43:41.188Z" +updated_at: "2026-10-18T07:46:52.729Z" +author: codex-agent +acceptance_criteria: "Train only on training repositories; preserve inner-held-out, meta-validation and final-test boundaries, fixed pre-approved budgets and unchanged promotion gate; report majority baselines, prediction diversity and final-test scores; demonstrate statistically supported improvement or explicitly report a null result without weakening the gate." +parent: pm-rl-apvf +files[1]{path,scope}: + tracker-environment.ts,project +docs[1]{path,scope}: + docs/meta-live-evidence.json,project +body: "" diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 3ee9eded..7d6d5d7e 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -39,3 +39,11 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T07:14:41.805Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:14:41.805Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"07daeeb1b5ccd2a086ca9061eb8b2012ad1a9c6cefd2221a0586087b94a514cc","after_hash":"efc58c462a97a675cc90c7690b2dbf4f2074f7df2e207d1cdefa016bbc28957a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7a851079b345556ece2207da535a42ef13ac3fb3cb2e7979841d7bf2f9c070e7"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:14:44.751Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/18","value":{"created_at":"2026-10-18T07:14:44.751Z","author":"codex-agent","text":"Final full-branch whitespace verification found one extra blank line at the end of tracker-environment.ts. Removed only that blank line; runtime statements, knobs, data and promotion criteria are unchanged. The full diff whitespace check now passes. The prior complete code gate remains 612/612 in all three CI variants; the formatting head will receive the same exact-command matrix before stopping. Release the claim after this formatting-only handoff; leave status in progress and closure to the orchestrator."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:14:44.751Z"}],"before_hash":"efc58c462a97a675cc90c7690b2dbf4f2074f7df2e207d1cdefa016bbc28957a","after_hash":"c24cbf775107d7699b546fa0026bd40157ead82075edbb247a85da1dd4998fcd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a4930d68341eba30eb9a778a258d666a91532404c58b2d7ac858ff177b9ead8d"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:14:46.977Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:14:46.977Z"}],"before_hash":"c24cbf775107d7699b546fa0026bd40157ead82075edbb247a85da1dd4998fcd","after_hash":"3c707eca73ec01c1f2f3c35b7643784a67c975d91ad3e215d2ab54469ab0112a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"c9d83cfea4b5361faaae482774b7105063c37817d20d9f6344301c18ba18db98"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:40:56.442Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:40:56.442Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"3c707eca73ec01c1f2f3c35b7643784a67c975d91ad3e215d2ab54469ab0112a","after_hash":"6958016be6d268e94ca1ecd0777552ef2bd9bf4a67110aebad140bfac16cb1d8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"8e56195d5bf0b5d78e8d9e99ed419b1c7d346e17fa1c82aa2b2bf30521348ade"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:41:06.105Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/19","value":{"created_at":"2026-10-18T07:41:06.103Z","author":"codex-agent","text":"Reopened implementation work for PR 84 orchestrator review: measure held-out majority baselines and aggregate prediction diversity, add a committed learnable-signal promotion sanity case at the unchanged live gate, and document a prefix-aware learner follow-up if real-data performance remains below baseline. Existing audits, CI evidence, and completed implementation are retained."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:41:06.105Z"}],"before_hash":"6958016be6d268e94ca1ecd0777552ef2bd9bf4a67110aebad140bfac16cb1d8","after_hash":"803202c15b19cbd9e77259b31ce706cd5220d578a6557fa2b5c34531933d049f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c5b91530faf109d2c68ab434aabab6cb26e1d17d4bbe0a82ee81a74d8fb70d81"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:43:42.013Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/22/path","value":"test/recipe.test.ts"},{"op":"replace","path":"/metadata/files/21/path","value":"test/meta.test.ts"},{"op":"replace","path":"/metadata/files/20/path","value":"test/lm-compose.test.ts"},{"op":"replace","path":"/metadata/files/19/path","value":"test/fixtures/tracker-signal.json"},{"op":"add","path":"/metadata/files/23","value":{"path":"tracker-environment.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:43:42.013Z"}],"before_hash":"803202c15b19cbd9e77259b31ce706cd5220d578a6557fa2b5c34531933d049f","after_hash":"ecd46e45c15279e7ce5dbbf66827d21ba9be35066c677d20cf2c54a39de835ae","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"744caa51607a20d66d93636c0f9f7cd407b1058eca03620648309a21537d0e1f"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:43:42.859Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/4","value":{"command":"node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T07:43:42.817Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:43:42.859Z"}],"before_hash":"ecd46e45c15279e7ce5dbbf66827d21ba9be35066c677d20cf2c54a39de835ae","after_hash":"a29d8110c4db03f8439cccfa9c4ea306eac5458738c90aee65bb8d84e4e87eac","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"7804bd97340fc41d59e6b78a02a421bc1f11e2bccd95e14d1e87b0e46f0bd26c"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:46:49.973Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/20","value":{"created_at":"2026-10-18T07:46:49.973Z","author":"codex-agent","text":"Review diagnosis on the retained live dataset: majority completed baseline is 211/214 on meta-validation and 384/385 on final-test, versus learner 107/214 and 198/385. All accepted weights are zero because no inner candidate passed promotion; recipes therefore share the same seed policy, rather than collapsing to a single predicted label. Prefix-aware learning is tracked in pm-rl-prefix. Committed tracker-signal fixture uses a declared known signal and the unchanged live criterion confidence 0.95, minimum 10, effect 0.01: generation 1 promotes with gain 0.0686, lower bound 0.03899585625398397; final score rises 5093/10000 to 5806/10000. No real-data threshold or feature changed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:46:49.973Z"}],"before_hash":"a29d8110c4db03f8439cccfa9c4ea306eac5458738c90aee65bb8d84e4e87eac","after_hash":"fa23a32438d414c20d30506a4fe6d4f913fea503ea66530fc24cd2709984200c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"18d315f48179df7672537bcfb1ee867fe0684e5cae16eca57fee24a20c8eb1eb"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:46:51.026Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/21","value":{"created_at":"2026-10-18T07:46:51.026Z","author":"codex-agent","text":"Behavior-only review revert proofs: restoring only openTrackerEnvironment to its pre-review implementation makes the synthetic majority/diversity regression fail 0/1 (missing diagnostics). Disabling only recipeSuccessor promotion makes the committed learnable-signal test fail 0/1 at its promotion assertion. Both source functions were restored; tests and fixture were retained. Full restored linked run follows."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:46:51.026Z"}],"before_hash":"fa23a32438d414c20d30506a4fe6d4f913fea503ea66530fc24cd2709984200c","after_hash":"eb1fc998336eb4295775204902ab5e35940298f6ae1fa1e48c75af50c0bf731a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"45b59fa3516d1b5b7bc16382446f99bdeaed24c85131e46381cd5662285de3d6"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:48:02.353Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/5/path","value":"README.md"},{"op":"replace","path":"/metadata/docs/4/path","value":"examples/meta-approval.md"},{"op":"replace","path":"/metadata/docs/3/path","value":"docs/meta-sanity-evidence.json"},{"op":"add","path":"/metadata/docs/6","value":{"path":"RECURSIVE_TRAINING.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:48:02.353Z"}],"before_hash":"eb1fc998336eb4295775204902ab5e35940298f6ae1fa1e48c75af50c0bf731a","after_hash":"60354bd44e29d018070b6cccfd2ae7ad26f40de46299b4ccf240a5620155f6c3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"0a3fc5390eb5bc4cc262bd5949cd0e64b3b5103ce89dfa7b8dfcb4e381b929a7"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:48:03.342Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/22","value":{"created_at":"2026-10-18T07:48:03.342Z","author":"codex-agent","text":"Restored linked PM review run passed 2/2 with zero failures, cancellations or skips. Synthetic majority/diversity checks and the committed learnable-signal outer-loop promotion both pass. Aggregate prediction diagnostics do not expose held-out examples or prediction vectors. The retained real snapshot predicts 108 completed and 106 cancelled on meta-validation, 199 completed and 186 cancelled on final-test; candidate disagreement is zero because all accepted checkpoints are the seed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:48:03.342Z"}],"before_hash":"60354bd44e29d018070b6cccfd2ae7ad26f40de46299b4ccf240a5620155f6c3","after_hash":"311496233c37aac70f7570a052b39d173134b663f3cac34547b8eaef801ad721","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f67fde501a8d7fedb4789826f6c365d3273881f40f90185651c20f0920d8b84f"} diff --git a/.agents/pm/history/pm-rl-prefix.jsonl b/.agents/pm/history/pm-rl-prefix.jsonl new file mode 100644 index 00000000..a625b815 --- /dev/null +++ b/.agents/pm/history/pm-rl-prefix.jsonl @@ -0,0 +1,3 @@ +{"hash_algorithm":"sha256","ts":"2026-10-18T07:43:41.188Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-rl-prefix"},{"op":"add","path":"/metadata/title","value":"Train a history-prefix learner on the public tracker environment"},{"op":"add","path":"/metadata/description","value":"PR 84 acceptance scored 107/214 on meta-validation versus the completed-majority baseline 211/214, and 198/385 on final-test versus 384/385. All candidates retained the zero-weight seed checkpoint because inner fits were refused. Add a bounded learner that actually reads the normalized history prefix, such as the existing LM adapter, on the sealed repository-split tracker environment."},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-10-18T07:43:41.188Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-18T07:43:41.188Z"},{"op":"add","path":"/metadata/author","value":"codex-agent"},{"op":"add","path":"/metadata/acceptance_criteria","value":"Train only on training repositories; preserve inner-held-out, meta-validation and final-test boundaries, fixed pre-approved budgets and unchanged promotion gate; report majority baselines, prediction diversity and final-test scores; demonstrate statistically supported improvement or explicitly report a null result without weakening the gate."},{"op":"add","path":"/metadata/parent","value":"pm-rl-apvf"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"d3b7105ff2a0a8f2b83fab66ac0482dec1ed2188a27530eaeec0691c097082d4","item_hash_version":3,"message":"","context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e488a3cce10bf0529c284371cd70d0c69d1626ce1123b32ea0fe43698febb1b7"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:46:51.893Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:46:51.893Z"},{"op":"add","path":"/metadata/files","value":[{"path":"tracker-environment.ts","scope":"project"}]}],"before_hash":"d3b7105ff2a0a8f2b83fab66ac0482dec1ed2188a27530eaeec0691c097082d4","after_hash":"15ef9164282f34c43ffa158eac303c16acba237cab0d739c714c0e904adff12b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"d969d7dca8c649e5b0e46655fef7f43247e31d90e0c579a579e272b21366cbbc"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:46:52.729Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:46:52.729Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/meta-live-evidence.json","scope":"project"}]}],"before_hash":"15ef9164282f34c43ffa158eac303c16acba237cab0d739c714c0e904adff12b","after_hash":"41bf411f5e784f40826db4b46b6b1054e1b772c50a6aaaa5c8d1030320081414","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"c06d759f615be2f27c64a3903e002bfec3f2811939b6556fb135d132aad68784"} diff --git a/README.md b/README.md index d7ac59b2..84b6a105 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,10 @@ public tracker repositories. Inner held-out data stays in its evaluator; the proposer has no dataset capability. A proxy-only gain is refused by the existing statistical gate. The final-test repositories are opened only after all recipe promotions, and report the initial versus selected policy without influencing -selection. [The meta-recursive contract](docs/meta-recursive.md) documents the +selection. Reports include constant-majority baselines, predicted-label counts and +pairwise candidate disagreement, computed inside the evaluator. The current +tracker learner does not beat that baseline; the committed signal sanity case +proves that real gain can promote under the same gate. [The meta-recursive contract](docs/meta-recursive.md) documents the data boundary, confidence assumptions, idempotent resume and measured real-data acceptance. Start with [the bounded programme](examples/meta-trackers.json) and `pm rl dataset build --from-trackers --output `. diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 0b1b7c61..4009650e 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -76,7 +76,16 @@ Adapters report structured progress and completion evidence over a documented st receipts. Live acceptance on the corrected source executes two meta-generations with two candidates each over 25 repositories and 1,767 examples. All four candidates score 107/214, gain 0, lower gain bound -0.21778781183411927; none - promotes. Final-test before/after is 198/385. No real-data improvement is claimed. + promotes. Final-test before/after is 198/385. The completed-majority baselines + are 211/214 on meta-validation and 384/385 on final-test: **the current learner + does not beat the majority baseline on real trackers**. Every candidate predicts + both labels (108 completed, 106 cancelled); all six candidate pairs disagree + on 0/214 examples because their accepted checkpoint is the zero-weight seed. + [pm-rl-prefix](.agents/pm/features/pm-rl-prefix.toon) tracks a learner that reads + the history prefix. A committed known-signal fixture promotes through the same + 0.95-confidence, ten-sample, 0.01-effect gate: gain 0.0686, lower bound + 0.03899585625398397, and final-test 5093/10000 to 5806/10000. This is a sanity + result, not real-tracker improvement. No gate or real feature was weakened. [Complete release verification](https://github.com/unbraind/pm-rl/actions/runs/39104826277) passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: 612/612 each, zero failures/skips, all four coverage metrics 100% across all diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index c0d0015e..b1284649 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -137,6 +137,42 @@ improvement is claimed, and the gate was not relaxed. Dataset build plus control execution took 92,238.673391 ms inside the command's unchanged 15-minute watchdog. +## Baseline and recipe sensitivity review + +The majority class is `completed`: a constant predictor scores **211/214 = +0.985981308411215** on meta-validation and **384/385 = 0.9974025974025974** on +final-test. These are descriptive split-majority baselines, computed inside the +evaluator; final-test statistics are released only after all selection ends. +**The current learner does not beat the majority baseline on real trackers.** + +Every candidate predicts two labels: 108 `completed` and 106 `cancelled` on +meta-validation. All six candidate pairs disagree on **0/214 = 0%** of examples, +as does every candidate versus the incumbent. Final-test predictions are 199 +`completed` and 186 `cancelled`, also unchanged. This is not a single-class +collapse: every inner fit was refused, so the accepted zero-weight seed policy +remained identical across recipes. The score diagnostics expose only aggregate +counts and disagreement rates, without held-out rows or prediction vectors. +[pm-rl-prefix](../.agents/pm/features/pm-rl-prefix.toon) tracks a bounded learner +that reads the history prefix, such as the existing LM adapter, while preserving +all split, budget and promotion boundaries. + +The committed [known-signal fixture](../test/fixtures/tracker-signal.json) uses +last-state sign as a deterministic learnable rule. Each compartment has distinct +prefixes and repository roles remain disjoint; its seed and weak initial recipe +are fixed in the fixture. The actual process fits and two-generation outer loop +use the live criterion unchanged: confidence 0.95, minimum ten samples and effect +0.01. With one candidate in each generation, family-wise allocation gives 0.975 +per comparison. Generation 1 promotes recipe `30eccf433a17` with score +**5629/10000**, incumbent **4943/10000**, gain **0.0686**, and lower gain bound +**0.03899585625398397**. Generation 2 retains that incumbent. Final-test improves +from **5093/10000 to 5806/10000**, above its **5000/10000** majority baseline. +[The complete sanity receipt](meta-sanity-evidence.json) is separate from the real +acceptance receipt. This proves conditional promotion; it makes no claim of +real-tracker learning. The synthetic baseline test also checks a balanced split, +a cancellation-majority subset, both-label and single-label policies, identical +predictions, and full disagreement. + + ## Release verification The [complete CI run](https://github.com/unbraind/pm-rl/actions/runs/39104826277) diff --git a/docs/meta-sanity-evidence.json b/docs/meta-sanity-evidence.json new file mode 100644 index 00000000..4ba76d15 --- /dev/null +++ b/docs/meta-sanity-evidence.json @@ -0,0 +1,247 @@ +{ + "format": "pm-rl/meta-sanity-evidence/1", + "command": "node --test --test-name-pattern=\"genuinely better\" test/meta.test.ts", + "fixture": "test/fixtures/tracker-signal.json", + "fixture_sha256": "31b09d18ace85a06043bdc151003746d8d91758282344d26adb259a20a12fc42", + "sanity": "committed tracker-signal", + "criterion": { + "confidence": 0.95, + "minSamples": 10, + "effectThreshold": 0.01 + }, + "generations": [ + { + "generation": 1, + "proposer": "seeded", + "candidates": [ + { + "candidate": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.9123291206313298, + "steps": 2, + "batch": 157, + "temperature": 0.5280031209113076, + "correct_weight": 0.9163122845347971, + "incorrect_weight": 0.16172463475959376, + "selection": "all", + "curriculum": "forward" + }, + "digest": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512" + }, + "weight": 0.3075010661567694, + "checkpoint": "sha256:72c93c24ecd8f92a3cfe4a458aced46b340e3beb4b102aa1d00a65fad964c2cb" + }, + "incumbent": "sha256:08c751cfa829b746529aefc0e9f6cfa92aa097535b71d0e8672e916c8fcda108", + "score": { + "mean": 0.5629, + "samples": 10000, + "context": "a3eedd5b7c9fc158fcf356b6c44515bf83ae808171ca0e5dc64bb6025e0945d5" + }, + "gain": 0.06859999999999994, + "gain_lower_bound": 0.03899585625398397, + "verdict": { + "decision": "promote", + "margin": 0.02899585625398394, + "candidateBound": 0.548097928126992, + "incumbentBound": 0.509102071873008, + "candidateEpsilon": 0.014802071873007982, + "incumbentEpsilon": 0.014802071873007982, + "reason": "Promoted: candidate lower bound 0.548098 beats incumbent upper bound 0.509102 by 0.028996 above the effect threshold, with confidence 0.975 over 10000 candidate and 10000 incumbent samples." + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 5000, + "samples": 10000, + "mean": 0.5 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 4985, + "cancelled": 5015 + } + }, + "disagreements": [ + { + "recipe": "sha256:08c751cfa829b746529aefc0e9f6cfa92aa097535b71d0e8672e916c8fcda108", + "differing": 686, + "samples": 10000, + "rate": 0.0686 + } + ] + } + } + ], + "promoted": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512" + }, + { + "generation": 2, + "proposer": "seeded", + "candidates": [ + { + "candidate": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.968875700214412, + "steps": 2, + "batch": 110, + "temperature": 1.287882182514295, + "correct_weight": 0.9813171887071803, + "incorrect_weight": 0.05578340287320316, + "selection": "balanced", + "curriculum": "forward" + }, + "digest": "sha256:5e3c044ca99125f38d0bc42c1628f38bf0c8eb78a998fc6e88f8e4b953b0a31e" + }, + "weight": 0, + "checkpoint": "sha256:17493680209cdf2fc86126ff2ad0b7bb6063ae24ce00f28f931224bb5ab2fd11" + }, + "incumbent": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", + "score": { + "mean": 0.4943, + "samples": 10000, + "context": "a3eedd5b7c9fc158fcf356b6c44515bf83ae808171ca0e5dc64bb6025e0945d5" + }, + "gain": -0.06859999999999994, + "gain_lower_bound": -0.09820414374601591, + "verdict": { + "decision": "refuse", + "code": "no_statistical_improvement", + "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.479498 does not beat incumbent upper bound 0.577702 by the effect threshold 0.01 (margin -0.108204). The candidate regressed: its mean is not above the incumbent's mean." + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 5000, + "samples": 10000, + "mean": 0.5 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 5017, + "cancelled": 4983 + } + }, + "disagreements": [ + { + "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", + "differing": 686, + "samples": 10000, + "rate": 0.0686 + } + ] + } + } + ], + "promoted": null + } + ], + "final_test": { + "before": { + "mean": 0.5093, + "samples": 10000, + "context": "82ae974b00902215d046957ef2cba601628408fc804b7156e4ad7f6be5bcde92" + }, + "after": { + "mean": 0.5806, + "samples": 10000, + "context": "82ae974b00902215d046957ef2cba601628408fc804b7156e4ad7f6be5bcde92" + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 5000, + "samples": 10000, + "mean": 0.5 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 4976, + "cancelled": 5024 + } + }, + "disagreements": [ + { + "recipe": "sha256:08c751cfa829b746529aefc0e9f6cfa92aa097535b71d0e8672e916c8fcda108", + "differing": 713, + "samples": 10000, + "rate": 0.0713 + } + ] + } + } +} diff --git a/meta.ts b/meta.ts index b52d1f2c..65bf64a7 100644 --- a/meta.ts +++ b/meta.ts @@ -25,6 +25,12 @@ export interface MetaConfig { export interface RecipePolicy { readonly recipe: Recipe; readonly weight: number; readonly checkpoint: string } /** Exact-match evidence counts distinct examples, rather than repeated pseudo-replications. */ export interface TrackerScore { readonly mean: number; readonly samples: number; readonly context: string } +/** Aggregate held-out diagnostics expose neither examples nor prediction vectors to search. */ +export interface TrackerDiagnostics { + readonly majority_class: { readonly label: "completed" | "cancelled"; readonly correct: number; readonly samples: number; readonly mean: number }; + readonly predictions: { readonly distinct_labels: number; readonly counts: Readonly> }; + readonly disagreements: readonly { readonly recipe: string; readonly differing: number; readonly samples: number; readonly rate: number }[]; +} /** Each comparison retains the actual gate, observed gain and conservative lower confidence bound. */ export interface MetaComparison { readonly candidate: RecipePolicy; @@ -34,12 +40,14 @@ export interface MetaComparison { readonly gain_lower_bound: number; readonly verdict: PromotionDecision; } +/** A sealed evaluation augments the gate evidence with descriptive baselines and diversity. */ +export interface EvaluatedRecipe extends MetaComparison { readonly diagnostics: TrackerDiagnostics } /** Final reports expose selection evidence and only then the untouched final-test comparison. */ export interface MetaReport { readonly initial: RecipePolicy; readonly incumbent: RecipePolicy; - readonly generations: readonly { readonly generation: number; readonly proposer: string; readonly candidates: readonly MetaComparison[]; readonly promoted: string | null }[]; - readonly final_test: { readonly before: TrackerScore; readonly after: TrackerScore }; + readonly generations: readonly { readonly generation: number; readonly proposer: string; readonly candidates: readonly EvaluatedRecipe[]; readonly promoted: string | null }[]; + readonly final_test: { readonly before: TrackerScore; readonly after: TrackerScore; readonly diagnostics: TrackerDiagnostics }; readonly dataset: string; } /** Public command request; filesystem coordinates never enter recipe or programme identities. */ @@ -238,16 +246,16 @@ export async function runRlMeta(client: PmClient, coordinates: ProcessCoordinate const incumbent = incumbents.at(-1)!; const proposals = await step(`m${generation}-proposals`, { incumbent: incumbent.recipe.digest }, async () => await durableRecipeProposals(client, request.id, proposalRequest, incumbent.recipe, generation, signal) as unknown as JsonValue) as unknown as Awaited>; - const candidates: MetaComparison[] = []; + const candidates: EvaluatedRecipe[] = []; for (const [index, recipe] of proposals.recipes.entries()) { const policy = await step(`m${generation}-c${index}`, { recipe: recipe.digest }, async () => await environment.fit(recipe, `${request.id}-m${generation}-c${index}`, signal) as unknown as JsonValue) as unknown as RecipePolicy; const comparison = await step(`m${generation}-score${index}`, { candidate: policy.checkpoint, incumbent: incumbent.recipe.digest }, async () => { - const { score, baseline } = environment.selection(policy, incumbent); + const { score, baseline, diagnostics } = environment.selection(policy, incumbent, [...generations.flatMap((previous) => previous.candidates), ...candidates].map((previous) => previous.candidate)); // Allocate family-wise error across all planned comparisons; search cannot relax the declared gate. const criterion = { ...config.criterion, confidence: 1 - (1 - config.criterion.confidence) / (config.meta_generations * config.candidates) }; - return compareRecipes(policy, incumbent, score, baseline, criterion) as unknown as JsonValue; - }) as unknown as MetaComparison; + return { ...compareRecipes(policy, incumbent, score, baseline, criterion), diagnostics } as unknown as JsonValue; + }) as unknown as EvaluatedRecipe; candidates.push(comparison); } const promoted = await step(`m${generation}-promote`, { incumbent: incumbent.recipe.digest, candidates: candidates as unknown as JsonValue }, async () => { diff --git a/test/fixtures/tracker-signal.json b/test/fixtures/tracker-signal.json new file mode 100644 index 00000000..95838c85 --- /dev/null +++ b/test/fixtures/tracker-signal.json @@ -0,0 +1,430 @@ +{ + "description": "Known learnable signal: a last blocked state predicts cancellation; every other last state predicts completion. Seed and recipe are fixed before evaluation. Each compartment has different prefixes with strong bounded features; the initial low-rate recipe is deliberately inadequate. No real-data claim follows from this sanity fixture.", + "seed": 198, + "initial_knobs": { + "learning_rate": 0.01, + "steps": 1, + "batch": 16, + "temperature": 2, + "correct_weight": 1, + "incorrect_weight": 0, + "selection": "all", + "curriculum": "forward" + }, + "splits": { + "train": { + "repetitions": 64, + "patterns": [ + { + "prefix": [ + "open", + "blocked", + "in_progress" + ], + "label": "completed" + }, + { + "prefix": [ + "open", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked" + ], + "label": "cancelled" + } + ] + }, + "inner-held-out": { + "repetitions": 64, + "patterns": [ + { + "prefix": [ + "open", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress" + ], + "label": "completed" + }, + { + "prefix": [ + "open", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked" + ], + "label": "cancelled" + } + ] + }, + "meta-validation": { + "repetitions": 5000, + "patterns": [ + { + "prefix": [ + "open", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress" + ], + "label": "completed" + }, + { + "prefix": [ + "open", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked" + ], + "label": "cancelled" + } + ] + }, + "final-test": { + "repetitions": 5000, + "patterns": [ + { + "prefix": [ + "open", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress" + ], + "label": "completed" + }, + { + "prefix": [ + "open", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked", + "in_progress", + "blocked" + ], + "label": "cancelled" + } + ] + } + } +} diff --git a/test/meta.test.ts b/test/meta.test.ts index 5a6350e0..6f640587 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -12,12 +12,12 @@ import extension, { hashJson, withRlController, type JsonValue, type RlCommandRe import { compareRecipes, durableRecipeProposals, metaReservation, parseMetaConfig, proposeRecipes, recipeExamples, recipeSuccessor, runRlMeta, scoreTrackerPolicy, type MetaConfig, type MetaRequest } from "../meta.ts"; import { INITIAL_RECIPE, recipeArtifact, seededRecipes } from "../recipe.ts"; import { banditCheckpoint } from "../bandit.ts"; -import { readTrackerSplit, type TrackerDataset } from "../dataset.ts"; +import { readTrackerSplit, type TrackerDataset, type TrackerExample, TRACKER_SPLITS } from "../dataset.ts"; import { listProcessJobs } from "../process.ts"; import { metaConfig, metaSpec, metaWorkspace, withTrackerSources } from "./fixtures/meta-workspace.ts"; import { liveMetaConfiguration, liveMetaMain, liveMetaOptions, printLiveMetaEvidence, publicTrackerDirectories, runLiveMetaAcceptance } from "../scripts/live-meta.ts"; import { runLiveCommand } from "../scripts/live-watchdog.ts"; -import { openTrackerEnvironment } from "../tracker-environment.ts"; +import { openTrackerEnvironment, trackerDiagnostics } from "../tracker-environment.ts"; /** Bind a bounded request to the real temporary tracker and synthetic committed sources. */ function requestFor(workspace: Awaited>, id: string, config = metaConfig): MetaRequest { @@ -60,10 +60,39 @@ test("reward shaping, selection, ordering and temperature affect training only; assert.equal(compareRecipes(candidate, incumbent, { ...score, context: "different" }, score, criterion).verdict.decision, "refuse"); }); +test("synthetic held-out splits report majority baselines and deterministic prediction diversity", async () => { + const w = await metaWorkspace(); + const environment = openTrackerEnvironment(w.client, w.coordinates, w.dataset, metaConfig, w.approval); + const seed = { recipe: INITIAL_RECIPE, weight: 0, checkpoint: banditCheckpoint(0).digest }; + const same = { ...seed, recipe: recipeArtifact({ ...INITIAL_RECIPE.knobs, learning_rate: 1 }) }; + const comparison = environment.selection(same, seed); + const final = environment.finalTest(seed, same); + for (const diagnostics of [comparison.diagnostics, final.diagnostics]) { + assert.deepEqual(diagnostics.majority_class, { label: "completed", correct: 16, samples: 32, mean: 0.5 }); + assert.equal(diagnostics.predictions.distinct_labels, 2); + assert.equal(diagnostics.predictions.counts.completed + diagnostics.predictions.counts.cancelled, 32); + assert.deepEqual(diagnostics.disagreements, [{ recipe: seed.recipe.digest, differing: 0, samples: 32, rate: 0 }]); + } + assert.deepEqual(environment.selection(same, seed), comparison); + const examples = readTrackerSplit(w.dataset, w.manifest, "meta-validation"); + const positive = { ...same, weight: 1000 }; const negative = { ...seed, weight: -1000 }; + const polarized = environment.selection(positive, negative, [seed]); + assert.equal(polarized.diagnostics.disagreements[0].rate, 1); + assert.ok(polarized.diagnostics.disagreements[1].rate > 0 && polarized.diagnostics.disagreements[1].rate < 1); + const cancelled = examples.filter((example) => example.label === "cancelled"); + const constant = trackerDiagnostics(cancelled, positive, [], metaConfig.seed); + assert.deepEqual(constant.majority_class, { label: "cancelled", correct: 16, samples: 16, mean: 1 }); + assert.deepEqual(constant.predictions, { distinct_labels: 1, counts: { completed: 0, cancelled: 16 } }); + const completed = trackerDiagnostics(examples.filter((example) => example.label === "completed"), positive, [], metaConfig.seed); + assert.deepEqual(completed.predictions, { distinct_labels: 1, counts: { completed: 16, cancelled: 0 } }); + assert.throws(() => trackerDiagnostics([], seed, [], 42), /meta_diagnostics_empty/); +}); + test("two real meta generations retain recipes and process jobs, then resume without double charge or reading inner/final splits", { timeout: 600_000 }, async () => { const w = await metaWorkspace(); const request = requestFor(w, "recursive"); const phases: string[] = []; const first = await runRlMeta(w.client, w.coordinates, { ...request, onStep(key) { phases.push(key); } }); assert.equal(first.generations.length, 2); assert.ok(first.generations.every((generation) => generation.candidates.length === 2)); + assert.deepEqual(first.generations.flatMap((generation) => generation.candidates.map((candidate) => candidate.diagnostics.disagreements.length)), [1, 2, 3, 4]); assert.equal(first.generations[1].candidates[0].incumbent, first.generations[0].promoted ?? first.initial.recipe.digest); assert.ok(phases.indexOf("final-test") > phases.indexOf("m2-promote")); const jobs = await listProcessJobs(w.client); assert.ok(jobs.length >= 5); @@ -119,26 +148,36 @@ test("a real outer SIGKILL adopts the committed fit and its original settled res } }); -test("a genuinely better recipe clears the unchanged gate and becomes the next meta generation incumbent", { timeout: 600_000 }, async () => { +test("a genuinely better recipe clears the unchanged gate and becomes the next meta generation incumbent", { timeout: 600_000 }, async (context) => { const w = await metaWorkspace(); - const initial = recipeArtifact({ ...INITIAL_RECIPE.knobs, learning_rate: 0.01, steps: 1, batch: 16, temperature: 2 }); - let seed = 0; - for (; seed < 1000; seed += 1) { - const candidate = seededRecipes(initial, seed, 1, 1)[0].knobs; - if (candidate.steps * candidate.learning_rate * (candidate.correct_weight - candidate.incorrect_weight) / candidate.temperature ** 2 > 4) break; + const fixture = JSON.parse(readFileSync(new URL("./fixtures/tracker-signal.json", import.meta.url), "utf8")) as { + seed: number; initial_knobs: typeof INITIAL_RECIPE.knobs; + splits: Record[] }>; + }; + const initial = recipeArtifact(fixture.initial_knobs); + const splits = { ...w.manifest.splits }; + for (const split of TRACKER_SPLITS) { + const source = readTrackerSplit(w.dataset, w.manifest, split)[0]; + const signal = fixture.splits[split]; + const expanded = Array.from({ length: signal.repetitions * signal.patterns.length }, (_, index) => ({ + ...source, ...signal.patterns[index % signal.patterns.length], id: hashJson({ index, split, fixture: "known-signal" }), + })); + writeFileSync(join(w.dataset, `${split}.json`), JSON.stringify(expanded)); + splits[split] = { count: expanded.length, digest: hashJson(expanded as unknown as JsonValue) }; } - assert.ok(seed < 1000, "synthetic high-signal recipe fixture exists"); - const examples = readTrackerSplit(w.dataset, w.manifest, "meta-validation"); - const expanded = Array.from({ length: 10_000 }, (_, index) => ({ ...examples[index % examples.length], id: hashJson({ index, fixture: true }) })); - writeFileSync(join(w.dataset, "meta-validation.json"), JSON.stringify(expanded)); - const { digest: _digest, ...record } = { ...w.manifest, splits: { ...w.manifest.splits, "meta-validation": { count: expanded.length, digest: hashJson(expanded as unknown as JsonValue) } } }; + const { digest: _digest, ...record } = { ...w.manifest, splits }; const manifest: TrackerDataset = { ...record, digest: hashJson(record as unknown as JsonValue) }; writeFileSync(join(w.dataset, "dataset.json"), JSON.stringify(manifest)); - const report = await runRlMeta(w.client, w.coordinates, requestFor(w, "improvement", { ...metaConfig, initial_recipe: initial, seed, candidates: 1, evaluation_samples: 100_000 })); + const report = await runRlMeta(w.client, w.coordinates, requestFor(w, "improvement", { ...liveMetaConfiguration(), initial_recipe: initial, seed: fixture.seed, candidates: 1, evaluation_samples: 100_000 })); + context.diagnostic(JSON.stringify({ sanity: "committed tracker-signal", criterion: liveMetaConfiguration().criterion, generations: report.generations, final_test: report.final_test })); assert.ok(report.generations[0].promoted !== null); assert.equal(report.generations[1].candidates[0].incumbent, report.generations[0].promoted); const first = report.generations[0].candidates[0]; assert.equal(first.verdict.decision, "promote"); - assert.ok(first.gain_lower_bound >= metaConfig.criterion.effectThreshold); + assert.ok(first.gain_lower_bound >= liveMetaConfiguration().criterion.effectThreshold); + assert.equal(first.verdict.candidateEpsilon, Math.sqrt(Math.log(2 / (1 - 0.975)) / (2 * splits["meta-validation"].count))); + assert.ok(first.diagnostics.disagreements[0].rate > 0); + assert.ok(report.final_test.after.mean > report.final_test.before.mean + liveMetaConfiguration().criterion.effectThreshold); + assert.ok(report.final_test.after.mean > report.final_test.diagnostics.majority_class.mean); }); test("an interrupted atomic search reservation is retained once, including drift refusal on resume", { timeout: 600_000 }, async () => { diff --git a/tracker-environment.ts b/tracker-environment.ts index 1710a2d3..1094b026 100644 --- a/tracker-environment.ts +++ b/tracker-environment.ts @@ -8,13 +8,13 @@ import { parseStoredLoopGeneration } from "./loop.ts"; import { parseGenerationSpec } from "./lineage.ts"; import type { ProcessCoordinates } from "./process.ts"; import type { Recipe } from "./recipe.ts"; -import type { MetaConfig, MetaRequest, MetaReport, RecipePolicy, TrackerScore } from "./meta.ts"; +import type { MetaConfig, MetaRequest, MetaReport, RecipePolicy, TrackerScore, TrackerDiagnostics } from "./meta.ts"; /** The outer search has no dataset coordinate or example-reading method. */ export interface TrackerEnvironment { readonly digest: string; fit(recipe: Recipe, id: string, signal: AbortSignal): Promise; - selection(candidate: RecipePolicy, incumbent: RecipePolicy): { score: TrackerScore; baseline: TrackerScore }; + selection(candidate: RecipePolicy, incumbent: RecipePolicy, peers?: readonly RecipePolicy[]): { score: TrackerScore; baseline: TrackerScore; diagnostics: TrackerDiagnostics }; finalTest(initial: RecipePolicy, incumbent: RecipePolicy): MetaReport["final_test"]; } @@ -24,15 +24,17 @@ export function openTrackerEnvironment(client: PmClient, coordinates: ProcessCoo return { digest: manifest.digest, fit: async (recipe, id, signal) => fitRecipe(client, coordinates, { config, dataset: directory, approval }, manifest, recipe, id, signal), - selection(candidate, incumbent) { + selection(candidate, incumbent, peers = []) { const examples = readTrackerSplit(directory, manifest, "meta-validation"); const context = manifest.splits["meta-validation"].digest; - return { score: scoreTrackerPolicy(examples, candidate, context, config.seed), baseline: scoreTrackerPolicy(examples, incumbent, context, config.seed) }; + return { score: scoreTrackerPolicy(examples, candidate, context, config.seed), baseline: scoreTrackerPolicy(examples, incumbent, context, config.seed), + diagnostics: trackerDiagnostics(examples, candidate, [incumbent, ...peers], config.seed) }; }, finalTest(initial, incumbent) { const examples = readTrackerSplit(directory, manifest, "final-test"); const context = manifest.splits["final-test"].digest; - return { before: scoreTrackerPolicy(examples, initial, context, config.seed), after: scoreTrackerPolicy(examples, incumbent, context, config.seed) }; + return { before: scoreTrackerPolicy(examples, initial, context, config.seed), after: scoreTrackerPolicy(examples, incumbent, context, config.seed), + diagnostics: trackerDiagnostics(examples, incumbent, [initial], config.seed) }; }, }; } @@ -56,18 +58,39 @@ export function recipeExamples(examples: readonly TrackerExample[], recipe: Reci }); } -/** Sample one action per unique prefix on a stream shared across policies, rewarding only exact class matches. */ -export function scoreTrackerPolicy(examples: readonly TrackerExample[], policy: RecipePolicy, context: string, seed: number): TrackerScore { - let correct = 0; - for (const example of examples) { +/** Sample reproducible policy actions inside the evaluator; never return these vectors to outer search. */ +function trackerPredictions(examples: readonly TrackerExample[], policy: RecipePolicy, seed: number): ("completed" | "cancelled")[] { + return examples.map((example) => { const draw = Number.parseInt(hashJson({ seed, id: example.id }).slice(7, 15), 16) / 0x100000000; const probability = 1 / (1 + Math.exp(-policy.weight * trackerFeature(example) / policy.recipe.knobs.temperature)); - const prediction = draw < probability ? "completed" : "cancelled"; - if (prediction === example.label) correct += 1; - } + return draw < probability ? "completed" : "cancelled"; + }); +} + +/** Sample one action per unique prefix on a stream shared across policies, rewarding only exact class matches. */ +export function scoreTrackerPolicy(examples: readonly TrackerExample[], policy: RecipePolicy, context: string, seed: number): TrackerScore { + const predictions = trackerPredictions(examples, policy, seed); + const correct = examples.filter((example, index) => predictions[index] === example.label).length; return { mean: correct / examples.length, samples: examples.length, context }; } +/** Measure the split's constant-majority baseline and pairwise disagreement without releasing held-out rows. */ +export function trackerDiagnostics(examples: readonly TrackerExample[], policy: RecipePolicy, peers: readonly RecipePolicy[], seed: number): TrackerDiagnostics { + assert.ok(examples.length > 0, "meta_diagnostics_empty"); + const completed = examples.filter((example) => example.label === "completed").length; + const label = completed >= examples.length - completed ? "completed" : "cancelled"; + const correct = Math.max(completed, examples.length - completed); + const predictions = trackerPredictions(examples, policy, seed); + const counts = { completed: predictions.filter((prediction) => prediction === "completed").length, cancelled: predictions.filter((prediction) => prediction === "cancelled").length }; + return { majority_class: { label, correct, samples: examples.length, mean: correct / examples.length }, + predictions: { distinct_labels: Number(counts.completed > 0) + Number(counts.cancelled > 0), counts }, + disagreements: peers.map((peer) => { + const other = trackerPredictions(examples, peer, seed); + const differing = predictions.filter((prediction, index) => prediction !== other[index]).length; + return { recipe: peer.recipe.digest, differing, samples: examples.length, rate: differing / examples.length }; + }) }; +} + /** Run the inner loop behind a compartment boundary; its held-out examples and scores never return to search. */ async function fitRecipe(client: PmClient, coordinates: ProcessCoordinates, request: Pick, manifest: TrackerDataset, recipe: Recipe, id: string, signal: AbortSignal): Promise { const training = recipeExamples(readTrackerSplit(request.dataset, manifest, "train"), recipe, true); From 3fe565dcb70ff975a7a5c3f9b5b353768af0b577 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 09:50:20 +0200 Subject: [PATCH 08/24] docs: record live majority baselines and candidate disagreement --- .agents/pm/features/pm-rl-meta.toon | 5 +- .agents/pm/history/pm-rl-meta.jsonl | 1 + docs/meta-live-evidence.json | 155 +++++++++++++++++++++++++++- docs/meta-recursive.md | 4 +- 4 files changed, 159 insertions(+), 6 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index f03835e1..a884a9e5 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T07:48:03.342Z" +updated_at: "2026-10-18T07:50:16.520Z" assignee: codex-agent claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[23]{created_at,author,text}: +comments[24]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -36,6 +36,7 @@ comments[23]{created_at,author,text}: "2026-10-18T07:46:49.973Z",codex-agent,"Review diagnosis on the retained live dataset: majority completed baseline is 211/214 on meta-validation and 384/385 on final-test, versus learner 107/214 and 198/385. All accepted weights are zero because no inner candidate passed promotion; recipes therefore share the same seed policy, rather than collapsing to a single predicted label. Prefix-aware learning is tracked in pm-rl-prefix. Committed tracker-signal fixture uses a declared known signal and the unchanged live criterion confidence 0.95, minimum 10, effect 0.01: generation 1 promotes with gain 0.0686, lower bound 0.03899585625398397; final score rises 5093/10000 to 5806/10000. No real-data threshold or feature changed." "2026-10-18T07:46:51.026Z",codex-agent,"Behavior-only review revert proofs: restoring only openTrackerEnvironment to its pre-review implementation makes the synthetic majority/diversity regression fail 0/1 (missing diagnostics). Disabling only recipeSuccessor promotion makes the committed learnable-signal test fail 0/1 at its promotion assertion. Both source functions were restored; tests and fixture were retained. Full restored linked run follows." "2026-10-18T07:48:03.342Z",codex-agent,"Restored linked PM review run passed 2/2 with zero failures, cancellations or skips. Synthetic majority/diversity checks and the committed learnable-signal outer-loop promotion both pass. Aggregate prediction diagnostics do not expose held-out examples or prediction vectors. The retained real snapshot predicts 108 completed and 106 cancelled on meta-validation, 199 completed and 186 cancelled on final-test; candidate disagreement is zero because all accepted checkpoints are the seed." + "2026-10-18T07:50:16.520Z",codex-agent,"Bounded npm run test:live rerun passed in 58251.420959 ms on production source 5a142fc38a2591eb464ce63819f32f7101c2a9ef. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c and all original scores, recipes, checkpoints and refusal verdicts are reproduced. Two meta-generations, K=2: all four candidates score 107/214, gain 0, lower bound -0.21778781183411927; none promotes. Majority baseline completed is 211/214 (0.985981308411215). Each candidate predicts 108 completed and 106 cancelled; every one of six candidate pairs and every candidate versus incumbent disagrees on 0/214 (0%). Final before/after 198/385 (0.5142857142857142), majority baseline 384/385 (0.9974025974025974), predictions 199 completed and 186 cancelled. The learner does not beat the baseline. Live receipt now includes these evaluator-produced aggregates; pm-rl-prefix tracks the learner improvement. All budgets, knobs, split identities and the statistical gate are unchanged." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 7d6d5d7e..d9ac899d 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -47,3 +47,4 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T07:46:51.026Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/21","value":{"created_at":"2026-10-18T07:46:51.026Z","author":"codex-agent","text":"Behavior-only review revert proofs: restoring only openTrackerEnvironment to its pre-review implementation makes the synthetic majority/diversity regression fail 0/1 (missing diagnostics). Disabling only recipeSuccessor promotion makes the committed learnable-signal test fail 0/1 at its promotion assertion. Both source functions were restored; tests and fixture were retained. Full restored linked run follows."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:46:51.026Z"}],"before_hash":"fa23a32438d414c20d30506a4fe6d4f913fea503ea66530fc24cd2709984200c","after_hash":"eb1fc998336eb4295775204902ab5e35940298f6ae1fa1e48c75af50c0bf731a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"45b59fa3516d1b5b7bc16382446f99bdeaed24c85131e46381cd5662285de3d6"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:48:02.353Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/5/path","value":"README.md"},{"op":"replace","path":"/metadata/docs/4/path","value":"examples/meta-approval.md"},{"op":"replace","path":"/metadata/docs/3/path","value":"docs/meta-sanity-evidence.json"},{"op":"add","path":"/metadata/docs/6","value":{"path":"RECURSIVE_TRAINING.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:48:02.353Z"}],"before_hash":"eb1fc998336eb4295775204902ab5e35940298f6ae1fa1e48c75af50c0bf731a","after_hash":"60354bd44e29d018070b6cccfd2ae7ad26f40de46299b4ccf240a5620155f6c3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"0a3fc5390eb5bc4cc262bd5949cd0e64b3b5103ce89dfa7b8dfcb4e381b929a7"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:48:03.342Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/22","value":{"created_at":"2026-10-18T07:48:03.342Z","author":"codex-agent","text":"Restored linked PM review run passed 2/2 with zero failures, cancellations or skips. Synthetic majority/diversity checks and the committed learnable-signal outer-loop promotion both pass. Aggregate prediction diagnostics do not expose held-out examples or prediction vectors. The retained real snapshot predicts 108 completed and 106 cancelled on meta-validation, 199 completed and 186 cancelled on final-test; candidate disagreement is zero because all accepted checkpoints are the seed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:48:03.342Z"}],"before_hash":"60354bd44e29d018070b6cccfd2ae7ad26f40de46299b4ccf240a5620155f6c3","after_hash":"311496233c37aac70f7570a052b39d173134b663f3cac34547b8eaef801ad721","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f67fde501a8d7fedb4789826f6c365d3273881f40f90185651c20f0920d8b84f"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:50:16.520Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/23","value":{"created_at":"2026-10-18T07:50:16.520Z","author":"codex-agent","text":"Bounded npm run test:live rerun passed in 58251.420959 ms on production source 5a142fc38a2591eb464ce63819f32f7101c2a9ef. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c and all original scores, recipes, checkpoints and refusal verdicts are reproduced. Two meta-generations, K=2: all four candidates score 107/214, gain 0, lower bound -0.21778781183411927; none promotes. Majority baseline completed is 211/214 (0.985981308411215). Each candidate predicts 108 completed and 106 cancelled; every one of six candidate pairs and every candidate versus incumbent disagrees on 0/214 (0%). Final before/after 198/385 (0.5142857142857142), majority baseline 384/385 (0.9974025974025974), predictions 199 completed and 186 cancelled. The learner does not beat the baseline. Live receipt now includes these evaluator-produced aggregates; pm-rl-prefix tracks the learner improvement. All budgets, knobs, split identities and the statistical gate are unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:50:16.520Z"}],"before_hash":"311496233c37aac70f7570a052b39d173134b663f3cac34547b8eaef801ad721","after_hash":"b412dc9469f0e7b018acaae360c701c0149b00c6bba6a10312d9cede77b0acb4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2284ad69d6a12532890151e2a5c88d428318bfff35793fa51c9694cde525e4c2"} diff --git a/docs/meta-live-evidence.json b/docs/meta-live-evidence.json index 10f83b29..514f58f1 100644 --- a/docs/meta-live-evidence.json +++ b/docs/meta-live-evidence.json @@ -359,6 +359,29 @@ "decision": "refuse", "code": "no_statistical_improvement", "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.391106 does not beat incumbent upper bound 0.608894 by the effect threshold 0.01 (margin -0.227788). The candidate regressed: its mean is not above the incumbent's mean." + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 211, + "samples": 214, + "mean": 0.985981308411215 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 108, + "cancelled": 106 + } + }, + "disagreements": [ + { + "recipe": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "differing": 0, + "samples": 214, + "rate": 0 + } + ] } }, { @@ -426,6 +449,35 @@ "decision": "refuse", "code": "no_statistical_improvement", "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.391106 does not beat incumbent upper bound 0.608894 by the effect threshold 0.01 (margin -0.227788). The candidate regressed: its mean is not above the incumbent's mean." + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 211, + "samples": 214, + "mean": 0.985981308411215 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 108, + "cancelled": 106 + } + }, + "disagreements": [ + { + "recipe": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "differing": 0, + "samples": 214, + "rate": 0 + }, + { + "recipe": "sha256:800886e9f4cd5b02c1ec5dacf8dd127649090ad0a14b8e70656df49ec5031b45", + "differing": 0, + "samples": 214, + "rate": 0 + } + ] } } ], @@ -500,6 +552,41 @@ "decision": "refuse", "code": "no_statistical_improvement", "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.391106 does not beat incumbent upper bound 0.608894 by the effect threshold 0.01 (margin -0.227788). The candidate regressed: its mean is not above the incumbent's mean." + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 211, + "samples": 214, + "mean": 0.985981308411215 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 108, + "cancelled": 106 + } + }, + "disagreements": [ + { + "recipe": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "differing": 0, + "samples": 214, + "rate": 0 + }, + { + "recipe": "sha256:800886e9f4cd5b02c1ec5dacf8dd127649090ad0a14b8e70656df49ec5031b45", + "differing": 0, + "samples": 214, + "rate": 0 + }, + { + "recipe": "sha256:45113586500fd8a5a6f9460ef6fa902dace8faaba2d3fc69791c9bfdfc52fe56", + "differing": 0, + "samples": 214, + "rate": 0 + } + ] } }, { @@ -567,6 +654,47 @@ "decision": "refuse", "code": "no_statistical_improvement", "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.391106 does not beat incumbent upper bound 0.608894 by the effect threshold 0.01 (margin -0.227788). The candidate regressed: its mean is not above the incumbent's mean." + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 211, + "samples": 214, + "mean": 0.985981308411215 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 108, + "cancelled": 106 + } + }, + "disagreements": [ + { + "recipe": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "differing": 0, + "samples": 214, + "rate": 0 + }, + { + "recipe": "sha256:800886e9f4cd5b02c1ec5dacf8dd127649090ad0a14b8e70656df49ec5031b45", + "differing": 0, + "samples": 214, + "rate": 0 + }, + { + "recipe": "sha256:45113586500fd8a5a6f9460ef6fa902dace8faaba2d3fc69791c9bfdfc52fe56", + "differing": 0, + "samples": 214, + "rate": 0 + }, + { + "recipe": "sha256:4a48567235f1fbca4e4a04c4b75ee3ac9586b613ea89641db727a03ef1c8c055", + "differing": 0, + "samples": 214, + "rate": 0 + } + ] } } ], @@ -583,11 +711,34 @@ "mean": 0.5142857142857142, "samples": 385, "context": "e47eacd557d0827f487b71019f8820e84b8a41a2727baa533239acf4ca97f4de" + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 384, + "samples": 385, + "mean": 0.9974025974025974 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 199, + "cancelled": 186 + } + }, + "disagreements": [ + { + "recipe": "sha256:b77fdfeff48dc713d46b397ff6ea652257fe46ca09650264ba5563e4e53a34ae", + "differing": 0, + "samples": 385, + "rate": 0 + } + ] } }, "dataset": "a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c" }, "dataset_build_and_controller_elapsed_ms": 93734.67408900001, - "elapsed_ms": 92238.67339099999, - "source_head": "c882cc2527ace62cff02af25a85b5bb30dedb2a4" + "elapsed_ms": 58251.420958999995, + "source_head": "5a142fc38a2591eb464ce63819f32f7101c2a9ef" } diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index b1284649..83608f2d 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -134,7 +134,7 @@ and reward bounds [0,1]. Each side's Hoeffding half-width is 0.10889390591705964. No recipe was promoted in either generation. The final-test score was **198/385 = 0.5142857142857142 before and after**. No real-data recipe improvement is claimed, and the gate was not relaxed. Dataset build plus controller -execution took 92,238.673391 ms inside the command's unchanged 15-minute watchdog. +execution took 58,251.420959 ms inside the command's unchanged 15-minute watchdog. ## Baseline and recipe sensitivity review @@ -182,7 +182,7 @@ Node 26 with isolated HOME and global/system Git configuration. Each passes all 35 declared sources, 295 documented declarations, and zero duplicate clones or production audit findings. Thresholds, dependency pins and release approval are unchanged. The live evidence names the measured production source commit; -the later resource-fixture changes affect acceptance tests only. +later receipt updates do not change the measured production source. The real Compose resource faults are explicit: the deadline worker publishes real LM progress then pauses past its unchanged 15-second limit; the memory From 030874dea041a32345e16cb9dd3791399bb50974 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 10:05:23 +0200 Subject: [PATCH 09/24] test: prove signal promotion with the exact live gate --- .agents/pm/features/pm-rl-meta.toon | 8 +- .agents/pm/history/pm-rl-meta.jsonl | 3 + RECURSIVE_TRAINING.md | 8 +- docs/meta-live-evidence.json | 2 +- docs/meta-recursive.md | 8 +- docs/meta-sanity-evidence.json | 249 ++++++++++++++++++++++++++-- test/meta.test.ts | 4 +- 7 files changed, 254 insertions(+), 28 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index a884a9e5..ab07133e 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T07:50:16.520Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T08:05:16.136Z" author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[24]{created_at,author,text}: +comments[26]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -37,6 +35,8 @@ comments[24]{created_at,author,text}: "2026-10-18T07:46:51.026Z",codex-agent,"Behavior-only review revert proofs: restoring only openTrackerEnvironment to its pre-review implementation makes the synthetic majority/diversity regression fail 0/1 (missing diagnostics). Disabling only recipeSuccessor promotion makes the committed learnable-signal test fail 0/1 at its promotion assertion. Both source functions were restored; tests and fixture were retained. Full restored linked run follows." "2026-10-18T07:48:03.342Z",codex-agent,"Restored linked PM review run passed 2/2 with zero failures, cancellations or skips. Synthetic majority/diversity checks and the committed learnable-signal outer-loop promotion both pass. Aggregate prediction diagnostics do not expose held-out examples or prediction vectors. The retained real snapshot predicts 108 completed and 106 cancelled on meta-validation, 199 completed and 186 cancelled on final-test; candidate disagreement is zero because all accepted checkpoints are the seed." "2026-10-18T07:50:16.520Z",codex-agent,"Bounded npm run test:live rerun passed in 58251.420959 ms on production source 5a142fc38a2591eb464ce63819f32f7101c2a9ef. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c and all original scores, recipes, checkpoints and refusal verdicts are reproduced. Two meta-generations, K=2: all four candidates score 107/214, gain 0, lower bound -0.21778781183411927; none promotes. Majority baseline completed is 211/214 (0.985981308411215). Each candidate predicts 108 completed and 106 cancelled; every one of six candidate pairs and every candidate versus incumbent disagrees on 0/214 (0%). Final before/after 198/385 (0.5142857142857142), majority baseline 384/385 (0.9974025974025974), predictions 199 completed and 186 cancelled. The learner does not beat the baseline. Live receipt now includes these evaluator-produced aggregates; pm-rl-prefix tracks the learner improvement. All budgets, knobs, split identities and the statistical gate are unchanged." + "2026-10-18T07:53:38.864Z",codex-agent,"Strengthened the committed signal sanity run to match the live programme exactly: two meta-generations, two candidates, 40000 inner evaluation samples, confidence 0.95 allocated as 0.9875 per outer comparison, minimum 10 and effect 0.01. It passes 2/2 focused tests: first candidate promotes with gain 0.0686 and lower bound 0.036740389785077876; generation 2 retains it; final score remains 5093/10000 to 5806/10000. No live rerun is needed for this test-only strengthening. Fresh no-local clone health passes after clone-local merge installation and isolated HOME; only the existing provenance advisory remains. PM histories preserve prior byte prefixes." + "2026-10-18T08:05:14.802Z",codex-agent,"Review release verification on 3fe565dcb70ff975a7a5c3f9b5b353768af0b577: CI run 39109179890 passes npm run release:check on Node 22 and Node 26 and bun run release:check on Node 26. Every variant passes 613/613, zero failures/cancellations/skips, exact 100% statements/lines/branches/functions over all 35 sources, 295 documented declarations, and unchanged identity, duplication, attestation, audit, packaging and changelog gates. The final stricter sanity configuration also passes the linked PM command 2/2: two generations, K=2, 40000 evaluation samples and the exact live criterion. Eight behavior-only revert proofs now cover the feature; both added review reverts fail with tests retained and restored code passes. Final receipt/test metadata is handed off for an additional exact-head CI run; production source is unchanged from measured live source 5a142fc. Release remains disabled; no items are closed. The real learner remains below the majority baseline; pm-rl-prefix is the open follow-up. Existing global extension version skew, the provenance advisory and disabled automatic PM result recording are retained rather than repaired or bypassed." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index d9ac899d..68eea822 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -48,3 +48,6 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T07:48:02.353Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/5/path","value":"README.md"},{"op":"replace","path":"/metadata/docs/4/path","value":"examples/meta-approval.md"},{"op":"replace","path":"/metadata/docs/3/path","value":"docs/meta-sanity-evidence.json"},{"op":"add","path":"/metadata/docs/6","value":{"path":"RECURSIVE_TRAINING.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:48:02.353Z"}],"before_hash":"eb1fc998336eb4295775204902ab5e35940298f6ae1fa1e48c75af50c0bf731a","after_hash":"60354bd44e29d018070b6cccfd2ae7ad26f40de46299b4ccf240a5620155f6c3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"0a3fc5390eb5bc4cc262bd5949cd0e64b3b5103ce89dfa7b8dfcb4e381b929a7"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:48:03.342Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/22","value":{"created_at":"2026-10-18T07:48:03.342Z","author":"codex-agent","text":"Restored linked PM review run passed 2/2 with zero failures, cancellations or skips. Synthetic majority/diversity checks and the committed learnable-signal outer-loop promotion both pass. Aggregate prediction diagnostics do not expose held-out examples or prediction vectors. The retained real snapshot predicts 108 completed and 106 cancelled on meta-validation, 199 completed and 186 cancelled on final-test; candidate disagreement is zero because all accepted checkpoints are the seed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:48:03.342Z"}],"before_hash":"60354bd44e29d018070b6cccfd2ae7ad26f40de46299b4ccf240a5620155f6c3","after_hash":"311496233c37aac70f7570a052b39d173134b663f3cac34547b8eaef801ad721","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f67fde501a8d7fedb4789826f6c365d3273881f40f90185651c20f0920d8b84f"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:50:16.520Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/23","value":{"created_at":"2026-10-18T07:50:16.520Z","author":"codex-agent","text":"Bounded npm run test:live rerun passed in 58251.420959 ms on production source 5a142fc38a2591eb464ce63819f32f7101c2a9ef. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c and all original scores, recipes, checkpoints and refusal verdicts are reproduced. Two meta-generations, K=2: all four candidates score 107/214, gain 0, lower bound -0.21778781183411927; none promotes. Majority baseline completed is 211/214 (0.985981308411215). Each candidate predicts 108 completed and 106 cancelled; every one of six candidate pairs and every candidate versus incumbent disagrees on 0/214 (0%). Final before/after 198/385 (0.5142857142857142), majority baseline 384/385 (0.9974025974025974), predictions 199 completed and 186 cancelled. The learner does not beat the baseline. Live receipt now includes these evaluator-produced aggregates; pm-rl-prefix tracks the learner improvement. All budgets, knobs, split identities and the statistical gate are unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:50:16.520Z"}],"before_hash":"311496233c37aac70f7570a052b39d173134b663f3cac34547b8eaef801ad721","after_hash":"b412dc9469f0e7b018acaae360c701c0149b00c6bba6a10312d9cede77b0acb4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2284ad69d6a12532890151e2a5c88d428318bfff35793fa51c9694cde525e4c2"} +{"hash_algorithm":"sha256","ts":"2026-10-18T07:53:38.864Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/24","value":{"created_at":"2026-10-18T07:53:38.864Z","author":"codex-agent","text":"Strengthened the committed signal sanity run to match the live programme exactly: two meta-generations, two candidates, 40000 inner evaluation samples, confidence 0.95 allocated as 0.9875 per outer comparison, minimum 10 and effect 0.01. It passes 2/2 focused tests: first candidate promotes with gain 0.0686 and lower bound 0.036740389785077876; generation 2 retains it; final score remains 5093/10000 to 5806/10000. No live rerun is needed for this test-only strengthening. Fresh no-local clone health passes after clone-local merge installation and isolated HOME; only the existing provenance advisory remains. PM histories preserve prior byte prefixes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:53:38.864Z"}],"before_hash":"b412dc9469f0e7b018acaae360c701c0149b00c6bba6a10312d9cede77b0acb4","after_hash":"2a1092641c7a2f70641377fa31c0dd756ff642d2e984885ba33e9ce5f5e92ad9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7783383a207efbfd2d0568822c103d976e295245c51e7839764f42ac4904b5f3"} +{"hash_algorithm":"sha256","ts":"2026-10-18T08:05:14.802Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/25","value":{"created_at":"2026-10-18T08:05:14.802Z","author":"codex-agent","text":"Review release verification on 3fe565dcb70ff975a7a5c3f9b5b353768af0b577: CI run 39109179890 passes npm run release:check on Node 22 and Node 26 and bun run release:check on Node 26. Every variant passes 613/613, zero failures/cancellations/skips, exact 100% statements/lines/branches/functions over all 35 sources, 295 documented declarations, and unchanged identity, duplication, attestation, audit, packaging and changelog gates. The final stricter sanity configuration also passes the linked PM command 2/2: two generations, K=2, 40000 evaluation samples and the exact live criterion. Eight behavior-only revert proofs now cover the feature; both added review reverts fail with tests retained and restored code passes. Final receipt/test metadata is handed off for an additional exact-head CI run; production source is unchanged from measured live source 5a142fc. Release remains disabled; no items are closed. The real learner remains below the majority baseline; pm-rl-prefix is the open follow-up. Existing global extension version skew, the provenance advisory and disabled automatic PM result recording are retained rather than repaired or bypassed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T08:05:14.802Z"}],"before_hash":"2a1092641c7a2f70641377fa31c0dd756ff642d2e984885ba33e9ce5f5e92ad9","after_hash":"12304bd996b5f8ce5dea9f05f6c61a984283f7324f450d8954f87cab905fb17d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"840a08b0934bd0e011ad5ddf33d0dd904d4def3f4f90c08a9b8d6eecadbabb7a"} +{"hash_algorithm":"sha256","ts":"2026-10-18T08:05:16.136Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T08:05:16.136Z"}],"before_hash":"12304bd996b5f8ce5dea9f05f6c61a984283f7324f450d8954f87cab905fb17d","after_hash":"658c4fe12fb0a67fb82fb3de48bbc4cc94f95bb1412d9046ade82bb2af4e851c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"c3ed9e5a1f17ba8efb7a01d08ff7834464decdf5e7d0d1562d55fa64a5ff3050"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 4009650e..683aaff3 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -84,13 +84,13 @@ Adapters report structured progress and completion evidence over a documented st [pm-rl-prefix](.agents/pm/features/pm-rl-prefix.toon) tracks a learner that reads the history prefix. A committed known-signal fixture promotes through the same 0.95-confidence, ten-sample, 0.01-effect gate: gain 0.0686, lower bound - 0.03899585625398397, and final-test 5093/10000 to 5806/10000. This is a sanity + 0.036740389785077876, and final-test 5093/10000 to 5806/10000. This is a sanity result, not real-tracker improvement. No gate or real feature was weakened. - [Complete release verification](https://github.com/unbraind/pm-rl/actions/runs/39104826277) + [Complete release verification](https://github.com/unbraind/pm-rl/pull/84/checks) passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: - 612/612 each, zero failures/skips, all four coverage metrics 100% across all + 613/613 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared - budget, conditional promotion and resource-refusal regressions pass; six + budget, conditional promotion and resource-refusal regressions pass; eight behaviour-only reverts fail with tests retained and restored code passes. diff --git a/docs/meta-live-evidence.json b/docs/meta-live-evidence.json index 514f58f1..0f4f32d3 100644 --- a/docs/meta-live-evidence.json +++ b/docs/meta-live-evidence.json @@ -738,7 +738,7 @@ }, "dataset": "a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c" }, - "dataset_build_and_controller_elapsed_ms": 93734.67408900001, + "dataset_build_and_controller_elapsed_ms": 58251.420958999995, "elapsed_ms": 58251.420958999995, "source_head": "5a142fc38a2591eb464ce63819f32f7101c2a9ef" } diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 83608f2d..0b971fcb 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -161,10 +161,10 @@ last-state sign as a deterministic learnable rule. Each compartment has distinct prefixes and repository roles remain disjoint; its seed and weak initial recipe are fixed in the fixture. The actual process fits and two-generation outer loop use the live criterion unchanged: confidence 0.95, minimum ten samples and effect -0.01. With one candidate in each generation, family-wise allocation gives 0.975 +0.01. With two candidates in each generation, family-wise allocation gives 0.9875 per comparison. Generation 1 promotes recipe `30eccf433a17` with score **5629/10000**, incumbent **4943/10000**, gain **0.0686**, and lower gain bound -**0.03899585625398397**. Generation 2 retains that incumbent. Final-test improves +**0.036740389785077876**. Generation 2 retains that incumbent. Final-test improves from **5093/10000 to 5806/10000**, above its **5000/10000** majority baseline. [The complete sanity receipt](meta-sanity-evidence.json) is separate from the real acceptance receipt. This proves conditional promotion; it makes no claim of @@ -175,10 +175,10 @@ predictions, and full disagreement. ## Release verification -The [complete CI run](https://github.com/unbraind/pm-rl/actions/runs/39104826277) +The [complete CI run](https://github.com/unbraind/pm-rl/pull/84/checks) executes `npm run release:check` on Node 22 and 26 and `bun run release:check` on Node 26 with isolated HOME and global/system Git configuration. Each passes -612/612 tests, zero failures/skips, 100% statements/lines/branches/functions over +613/613 tests, zero failures/skips, 100% statements/lines/branches/functions over all 35 declared sources, 295 documented declarations, and zero duplicate clones or production audit findings. Thresholds, dependency pins and release approval are unchanged. The live evidence names the measured production source commit; diff --git a/docs/meta-sanity-evidence.json b/docs/meta-sanity-evidence.json index 4ba76d15..1745d000 100644 --- a/docs/meta-sanity-evidence.json +++ b/docs/meta-sanity-evidence.json @@ -71,18 +71,18 @@ "score": { "mean": 0.5629, "samples": 10000, - "context": "a3eedd5b7c9fc158fcf356b6c44515bf83ae808171ca0e5dc64bb6025e0945d5" + "context": "db9287da5da16edda2be679e1fe67095489c8c395ca10799e6a4f7e06068c5ee" }, "gain": 0.06859999999999994, - "gain_lower_bound": 0.03899585625398397, + "gain_lower_bound": 0.036740389785077876, "verdict": { "decision": "promote", - "margin": 0.02899585625398394, - "candidateBound": 0.548097928126992, - "incumbentBound": 0.509102071873008, - "candidateEpsilon": 0.014802071873007982, - "incumbentEpsilon": 0.014802071873007982, - "reason": "Promoted: candidate lower bound 0.548098 beats incumbent upper bound 0.509102 by 0.028996 above the effect threshold, with confidence 0.975 over 10000 candidate and 10000 incumbent samples." + "margin": 0.026740389785077874, + "candidateBound": 0.546970194892539, + "incumbentBound": 0.5102298051074611, + "candidateEpsilon": 0.01592980510746103, + "incumbentEpsilon": 0.01592980510746103, + "reason": "Promoted: candidate lower bound 0.546970 beats incumbent upper bound 0.510230 by 0.026740 above the effect threshold, with confidence 0.9875 over 10000 candidate and 10000 incumbent samples." }, "diagnostics": { "majority_class": { @@ -107,6 +107,102 @@ } ] } + }, + { + "candidate": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.60342317444738, + "steps": 1, + "batch": 180, + "temperature": 0.5205776068614796, + "correct_weight": 0.931721021188423, + "incorrect_weight": 0.025413823139388114, + "selection": "all", + "curriculum": "reverse" + }, + "digest": "sha256:f151f1d6fbe87b93b1ebf031e06bdb5d3c2a5446865977b4c8f75e42857865cd" + }, + "weight": 0.14558497501150292, + "checkpoint": "sha256:1e409fbb0bb88277fae7c952bf273caabda09c95edcbac63c7f378cbf30d6be5" + }, + "incumbent": "sha256:08c751cfa829b746529aefc0e9f6cfa92aa097535b71d0e8672e916c8fcda108", + "score": { + "mean": 0.5265, + "samples": 10000, + "context": "db9287da5da16edda2be679e1fe67095489c8c395ca10799e6a4f7e06068c5ee" + }, + "gain": 0.03219999999999995, + "gain_lower_bound": 0.0003403897850778881, + "verdict": { + "decision": "refuse", + "code": "no_statistical_improvement", + "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.510570 does not beat incumbent upper bound 0.510230 by the effect threshold 0.01 (margin -0.009660)." + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 5000, + "samples": 10000, + "mean": 0.5 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 4983, + "cancelled": 5017 + } + }, + "disagreements": [ + { + "recipe": "sha256:08c751cfa829b746529aefc0e9f6cfa92aa097535b71d0e8672e916c8fcda108", + "differing": 322, + "samples": 10000, + "rate": 0.0322 + }, + { + "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", + "differing": 364, + "samples": 10000, + "rate": 0.0364 + } + ] + } } ], "promoted": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512" @@ -172,14 +268,116 @@ "score": { "mean": 0.4943, "samples": 10000, - "context": "a3eedd5b7c9fc158fcf356b6c44515bf83ae808171ca0e5dc64bb6025e0945d5" + "context": "db9287da5da16edda2be679e1fe67095489c8c395ca10799e6a4f7e06068c5ee" + }, + "gain": -0.06859999999999994, + "gain_lower_bound": -0.100459610214922, + "verdict": { + "decision": "refuse", + "code": "no_statistical_improvement", + "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.478370 does not beat incumbent upper bound 0.578830 by the effect threshold 0.01 (margin -0.110460). The candidate regressed: its mean is not above the incumbent's mean." + }, + "diagnostics": { + "majority_class": { + "label": "completed", + "correct": 5000, + "samples": 10000, + "mean": 0.5 + }, + "predictions": { + "distinct_labels": 2, + "counts": { + "completed": 5017, + "cancelled": 4983 + } + }, + "disagreements": [ + { + "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", + "differing": 686, + "samples": 10000, + "rate": 0.0686 + }, + { + "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", + "differing": 686, + "samples": 10000, + "rate": 0.0686 + }, + { + "recipe": "sha256:f151f1d6fbe87b93b1ebf031e06bdb5d3c2a5446865977b4c8f75e42857865cd", + "differing": 322, + "samples": 10000, + "rate": 0.0322 + } + ] + } + }, + { + "candidate": { + "recipe": { + "format": "pm-rl/recipe/1", + "bounds": { + "learning_rate": [ + 0.01, + 1 + ], + "steps": [ + 1, + 2 + ], + "batch": [ + 16, + 256 + ], + "temperature": [ + 0.5, + 2 + ], + "correct_weight": [ + 0.5, + 1 + ], + "incorrect_weight": [ + 0, + 0.25 + ], + "selection": [ + "all", + "balanced" + ], + "curriculum": [ + "forward", + "reverse" + ] + }, + "knobs": { + "learning_rate": 0.505095218901988, + "steps": 2, + "batch": 225, + "temperature": 1.2708191226702183, + "correct_weight": 0.684754868154414, + "incorrect_weight": 0.1074743561912328, + "selection": "all", + "curriculum": "forward" + }, + "digest": "sha256:75e5bd380335702f1461f2b253c1fff2dd42d32293880eae2e2227da7b23527a" + }, + "weight": 0, + "checkpoint": "sha256:17493680209cdf2fc86126ff2ad0b7bb6063ae24ce00f28f931224bb5ab2fd11" + }, + "incumbent": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", + "score": { + "mean": 0.4943, + "samples": 10000, + "context": "db9287da5da16edda2be679e1fe67095489c8c395ca10799e6a4f7e06068c5ee" }, "gain": -0.06859999999999994, - "gain_lower_bound": -0.09820414374601591, + "gain_lower_bound": -0.100459610214922, "verdict": { "decision": "refuse", "code": "no_statistical_improvement", - "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.479498 does not beat incumbent upper bound 0.577702 by the effect threshold 0.01 (margin -0.108204). The candidate regressed: its mean is not above the incumbent's mean." + "reason": "Promotion refused: the candidate is not statistically better than the incumbent. Candidate lower bound 0.478370 does not beat incumbent upper bound 0.578830 by the effect threshold 0.01 (margin -0.110460). The candidate regressed: its mean is not above the incumbent's mean." }, "diagnostics": { "majority_class": { @@ -201,6 +399,24 @@ "differing": 686, "samples": 10000, "rate": 0.0686 + }, + { + "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", + "differing": 686, + "samples": 10000, + "rate": 0.0686 + }, + { + "recipe": "sha256:f151f1d6fbe87b93b1ebf031e06bdb5d3c2a5446865977b4c8f75e42857865cd", + "differing": 322, + "samples": 10000, + "rate": 0.0322 + }, + { + "recipe": "sha256:5e3c044ca99125f38d0bc42c1628f38bf0c8eb78a998fc6e88f8e4b953b0a31e", + "differing": 0, + "samples": 10000, + "rate": 0 } ] } @@ -213,12 +429,12 @@ "before": { "mean": 0.5093, "samples": 10000, - "context": "82ae974b00902215d046957ef2cba601628408fc804b7156e4ad7f6be5bcde92" + "context": "7e0ba77a652c186c260bdf489aeaa0fadffaaf64a4849ec1ccf9505471359f66" }, "after": { "mean": 0.5806, "samples": 10000, - "context": "82ae974b00902215d046957ef2cba601628408fc804b7156e4ad7f6be5bcde92" + "context": "7e0ba77a652c186c260bdf489aeaa0fadffaaf64a4849ec1ccf9505471359f66" }, "diagnostics": { "majority_class": { @@ -243,5 +459,12 @@ } ] } + }, + "programme": { + "seed": 198, + "meta_generations": 2, + "candidates": 2, + "evaluation_samples": 40000, + "comparison_confidence": 0.9875 } } diff --git a/test/meta.test.ts b/test/meta.test.ts index 6f640587..7904c81a 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -168,13 +168,13 @@ test("a genuinely better recipe clears the unchanged gate and becomes the next m const { digest: _digest, ...record } = { ...w.manifest, splits }; const manifest: TrackerDataset = { ...record, digest: hashJson(record as unknown as JsonValue) }; writeFileSync(join(w.dataset, "dataset.json"), JSON.stringify(manifest)); - const report = await runRlMeta(w.client, w.coordinates, requestFor(w, "improvement", { ...liveMetaConfiguration(), initial_recipe: initial, seed: fixture.seed, candidates: 1, evaluation_samples: 100_000 })); + const report = await runRlMeta(w.client, w.coordinates, requestFor(w, "improvement", { ...liveMetaConfiguration(), initial_recipe: initial, seed: fixture.seed })); context.diagnostic(JSON.stringify({ sanity: "committed tracker-signal", criterion: liveMetaConfiguration().criterion, generations: report.generations, final_test: report.final_test })); assert.ok(report.generations[0].promoted !== null); assert.equal(report.generations[1].candidates[0].incumbent, report.generations[0].promoted); const first = report.generations[0].candidates[0]; assert.equal(first.verdict.decision, "promote"); assert.ok(first.gain_lower_bound >= liveMetaConfiguration().criterion.effectThreshold); - assert.equal(first.verdict.candidateEpsilon, Math.sqrt(Math.log(2 / (1 - 0.975)) / (2 * splits["meta-validation"].count))); + assert.equal(first.verdict.candidateEpsilon, Math.sqrt(Math.log(2 / (1 - 0.9875)) / (2 * splits["meta-validation"].count))); assert.ok(first.diagnostics.disagreements[0].rate > 0); assert.ok(report.final_test.after.mean > report.final_test.before.mean + liveMetaConfiguration().criterion.effectThreshold); assert.ok(report.final_test.after.mean > report.final_test.diagnostics.majority_class.mean); From 54b25736a6ea8ac5573cb829f38feaead84ea627 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 12:17:42 +0200 Subject: [PATCH 10/24] fix: isolate canonical meta receipts and bounded controller ids --- .agents/pm/features/pm-rl-meta.toon | 14 ++++- .agents/pm/history/pm-rl-meta.jsonl | 8 +++ README.md | 2 +- docs/meta-recursive.md | 31 ++++++++--- meta.ts | 34 ++++++++---- test/meta.test.ts | 85 ++++++++++++++++++++++++++++- 6 files changed, 149 insertions(+), 25 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index ab07133e..3fe9f724 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,11 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T08:05:16.136Z" +updated_at: "2026-10-18T10:17:13.734Z" +assignee: codex-agent +claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[26]{created_at,author,text}: +comments[31]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -37,6 +39,11 @@ comments[26]{created_at,author,text}: "2026-10-18T07:50:16.520Z",codex-agent,"Bounded npm run test:live rerun passed in 58251.420959 ms on production source 5a142fc38a2591eb464ce63819f32f7101c2a9ef. Dataset digest a4320672ba0d2f20e1aebfba7b9e91de71c95e17a9706700f79dfe163c8aae0c and all original scores, recipes, checkpoints and refusal verdicts are reproduced. Two meta-generations, K=2: all four candidates score 107/214, gain 0, lower bound -0.21778781183411927; none promotes. Majority baseline completed is 211/214 (0.985981308411215). Each candidate predicts 108 completed and 106 cancelled; every one of six candidate pairs and every candidate versus incumbent disagrees on 0/214 (0%). Final before/after 198/385 (0.5142857142857142), majority baseline 384/385 (0.9974025974025974), predictions 199 completed and 186 cancelled. The learner does not beat the baseline. Live receipt now includes these evaluator-produced aggregates; pm-rl-prefix tracks the learner improvement. All budgets, knobs, split identities and the statistical gate are unchanged." "2026-10-18T07:53:38.864Z",codex-agent,"Strengthened the committed signal sanity run to match the live programme exactly: two meta-generations, two candidates, 40000 inner evaluation samples, confidence 0.95 allocated as 0.9875 per outer comparison, minimum 10 and effect 0.01. It passes 2/2 focused tests: first candidate promotes with gain 0.0686 and lower bound 0.036740389785077876; generation 2 retains it; final score remains 5093/10000 to 5806/10000. No live rerun is needed for this test-only strengthening. Fresh no-local clone health passes after clone-local merge installation and isolated HOME; only the existing provenance advisory remains. PM histories preserve prior byte prefixes." "2026-10-18T08:05:14.802Z",codex-agent,"Review release verification on 3fe565dcb70ff975a7a5c3f9b5b353768af0b577: CI run 39109179890 passes npm run release:check on Node 22 and Node 26 and bun run release:check on Node 26. Every variant passes 613/613, zero failures/cancellations/skips, exact 100% statements/lines/branches/functions over all 35 sources, 295 documented declarations, and unchanged identity, duplication, attestation, audit, packaging and changelog gates. The final stricter sanity configuration also passes the linked PM command 2/2: two generations, K=2, 40000 evaluation samples and the exact live criterion. Eight behavior-only revert proofs now cover the feature; both added review reverts fail with tests retained and restored code passes. Final receipt/test metadata is handed off for an additional exact-head CI run; production source is unchanged from measured live source 5a142fc. Release remains disabled; no items are closed. The real learner remains below the majority baseline; pm-rl-prefix is the open follow-up. Existing global extension version skew, the provenance advisory and disabled automatic PM result recording are retained rather than repaired or bypassed." + "2026-10-18T09:41:56.517Z",codex-agent,"Review round on PR 84 head 030874d: read all three unresolved threads and the complete newest CodeRabbit review; there are zero open GitHub issues. Branch is nine commits ahead of main and not behind, so no main merge is required. Reusing this feature item to fix canonical reservation/proposal receipt lookup and envelope validation, reject programme ids that collide under the existing bounded lease namespace, and clarify the dataset CLI usage. Prior live evidence and statistical criteria remain unchanged." + "2026-10-18T09:42:17.714Z",codex-agent,Corrected the review-round claim to codex-agent after the first claim inherited the harness author. The mistaken claim event remains in append-only history; no history records are rewritten. + "2026-10-18T09:52:20.236Z",codex-agent,"All three review findings are fixed. Reservation and proposal receipt reads use the SDK-canonical key, validate Decision type and exact body id, treat only expected NOT_FOUND as absence, and propagate unreadable evidence. Proposal intent/completion envelopes now persist id without changing the binding. Programme ids are capped at 20: adding the longest eight-character inner suffix stays within the existing 28-character lease segment; 82 maximum-programme lease identities are distinct, and a real maximum-length run resumes without new jobs. README shows one from-trackers flag value followed by positional directories. Four independent behavior-only reverts each fail 0/1 with tests retained: reserveMeta selects a foreign prefixed reservation and drifts; durableRecipeProposals adopts a foreign completed result; removing only the id-length bound reaches writes for oversize ids; restoring only the README line makes the documented-command build fail. All fixes restored; linked restored verification follows." + "2026-10-18T09:58:26.605Z",codex-agent,"Restored linked review command passed 6/6, zero failures/cancellations/skips, through pm test --run --progress. It covers canonical reservation/proposal collisions and envelope corruption, the maximum-length real programme plus idempotent resume, README-driven dataset construction, existing real decision-model fallback/replay, and SDK case-folded budget accounting. Build, test typecheck, lint, duplication and docstring gates pass. Running both full release commands with isolated HOME and global/system Git configuration before push; previous live scores and gate thresholds are retained." + "2026-10-18T10:17:13.734Z",codex-agent,"The duplicate local npm run used Node 26, isolated HOME/Git identity and a memory-backed scratch area. It was deliberately interrupted while still passing corruption/continuation cases because shared-host execution was substantially slower than the existing complete CI runs. Its log is retained as incomplete, with no full-gate passing claim. Complete npm release:check on Node 22/26 and Bun release:check will run on the pushed head in the existing isolated CI matrix at unchanged thresholds. Focused linked verification remains 6/6 and four behavior-only reverts remain 0/1 each. No live-data rerun or statistical changes are needed for these receipt/lease/doc fixes." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project @@ -62,12 +69,13 @@ files[24]{path,scope}: test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[5]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[6]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts",project,600,codex-agent,"2026-10-18T06:35:18.894Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T07:43:42.817Z",local_mutation,feat/meta-recursive-recipe-loop + "node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T09:52:27.463Z",local_mutation,feat/meta-recursive-recipe-loop docs[7]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 68eea822..6db59fe6 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -51,3 +51,11 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T07:53:38.864Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/24","value":{"created_at":"2026-10-18T07:53:38.864Z","author":"codex-agent","text":"Strengthened the committed signal sanity run to match the live programme exactly: two meta-generations, two candidates, 40000 inner evaluation samples, confidence 0.95 allocated as 0.9875 per outer comparison, minimum 10 and effect 0.01. It passes 2/2 focused tests: first candidate promotes with gain 0.0686 and lower bound 0.036740389785077876; generation 2 retains it; final score remains 5093/10000 to 5806/10000. No live rerun is needed for this test-only strengthening. Fresh no-local clone health passes after clone-local merge installation and isolated HOME; only the existing provenance advisory remains. PM histories preserve prior byte prefixes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:53:38.864Z"}],"before_hash":"b412dc9469f0e7b018acaae360c701c0149b00c6bba6a10312d9cede77b0acb4","after_hash":"2a1092641c7a2f70641377fa31c0dd756ff642d2e984885ba33e9ce5f5e92ad9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7783383a207efbfd2d0568822c103d976e295245c51e7839764f42ac4904b5f3"} {"hash_algorithm":"sha256","ts":"2026-10-18T08:05:14.802Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/25","value":{"created_at":"2026-10-18T08:05:14.802Z","author":"codex-agent","text":"Review release verification on 3fe565dcb70ff975a7a5c3f9b5b353768af0b577: CI run 39109179890 passes npm run release:check on Node 22 and Node 26 and bun run release:check on Node 26. Every variant passes 613/613, zero failures/cancellations/skips, exact 100% statements/lines/branches/functions over all 35 sources, 295 documented declarations, and unchanged identity, duplication, attestation, audit, packaging and changelog gates. The final stricter sanity configuration also passes the linked PM command 2/2: two generations, K=2, 40000 evaluation samples and the exact live criterion. Eight behavior-only revert proofs now cover the feature; both added review reverts fail with tests retained and restored code passes. Final receipt/test metadata is handed off for an additional exact-head CI run; production source is unchanged from measured live source 5a142fc. Release remains disabled; no items are closed. The real learner remains below the majority baseline; pm-rl-prefix is the open follow-up. Existing global extension version skew, the provenance advisory and disabled automatic PM result recording are retained rather than repaired or bypassed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T08:05:14.802Z"}],"before_hash":"2a1092641c7a2f70641377fa31c0dd756ff642d2e984885ba33e9ce5f5e92ad9","after_hash":"12304bd996b5f8ce5dea9f05f6c61a984283f7324f450d8954f87cab905fb17d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"840a08b0934bd0e011ad5ddf33d0dd904d4def3f4f90c08a9b8d6eecadbabb7a"} {"hash_algorithm":"sha256","ts":"2026-10-18T08:05:16.136Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T08:05:16.136Z"}],"before_hash":"12304bd996b5f8ce5dea9f05f6c61a984283f7324f450d8954f87cab905fb17d","after_hash":"658c4fe12fb0a67fb82fb3de48bbc4cc94f95bb1412d9046ade82bb2af4e851c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"c3ed9e5a1f17ba8efb7a01d08ff7834464decdf5e7d0d1562d55fa64a5ff3050"} +{"hash_algorithm":"sha256","ts":"2026-10-18T09:41:55.452Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:41:55.452Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#7037d132570a6285e78b5af5"}],"before_hash":"658c4fe12fb0a67fb82fb3de48bbc4cc94f95bb1412d9046ade82bb2af4e851c","after_hash":"718942a963951ff90e1e9ef20af841e50ad390236b7329c77433e16ad3271e93","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"130456abad245eae63390611b104b543a077e06acf57d60808eca61fb1c6fd5e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T09:41:56.517Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/26","value":{"created_at":"2026-10-18T09:41:56.517Z","author":"codex-agent","text":"Review round on PR 84 head 030874d: read all three unresolved threads and the complete newest CodeRabbit review; there are zero open GitHub issues. Branch is nine commits ahead of main and not behind, so no main merge is required. Reusing this feature item to fix canonical reservation/proposal receipt lookup and envelope validation, reject programme ids that collide under the existing bounded lease namespace, and clarify the dataset CLI usage. Prior live evidence and statistical criteria remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:41:56.517Z"}],"before_hash":"718942a963951ff90e1e9ef20af841e50ad390236b7329c77433e16ad3271e93","after_hash":"d2da99ade7d25f6b61c68b2b01f3c621a470c9d09db32da056445257eabdd6b8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0a5a7c243e2fecca4e1cad8723b542859f5c503b3f6748606d269ef8515e6adc"} +{"hash_algorithm":"sha256","ts":"2026-10-18T09:42:15.643Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"claim","patch":[{"op":"replace","path":"/metadata/claim_principal","value":"codex-agent"},{"op":"replace","path":"/metadata/assignee","value":"codex-agent"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:42:15.643Z"}],"before_hash":"d2da99ade7d25f6b61c68b2b01f3c621a470c9d09db32da056445257eabdd6b8","after_hash":"f12c50a3fbd2f75494278a3731c503dbad7285f0d6db3ace7bac72131c0e522d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"145fef12eded631a05176dfb1a0719e6c2070d7a3f4fab73be170b3cf911d987"} +{"hash_algorithm":"sha256","ts":"2026-10-18T09:42:17.714Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/27","value":{"created_at":"2026-10-18T09:42:17.714Z","author":"codex-agent","text":"Corrected the review-round claim to codex-agent after the first claim inherited the harness author. The mistaken claim event remains in append-only history; no history records are rewritten."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:42:17.714Z"}],"before_hash":"f12c50a3fbd2f75494278a3731c503dbad7285f0d6db3ace7bac72131c0e522d","after_hash":"81c43e91267d14333613e5a375fd3ce5bb13534f1846b713eef210ae30d120fe","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e32dcd295396b8c043bf05194406393f00a0cec53aa818174ede5abbb9f09695"} +{"hash_algorithm":"sha256","ts":"2026-10-18T09:52:20.236Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/28","value":{"created_at":"2026-10-18T09:52:20.236Z","author":"codex-agent","text":"All three review findings are fixed. Reservation and proposal receipt reads use the SDK-canonical key, validate Decision type and exact body id, treat only expected NOT_FOUND as absence, and propagate unreadable evidence. Proposal intent/completion envelopes now persist id without changing the binding. Programme ids are capped at 20: adding the longest eight-character inner suffix stays within the existing 28-character lease segment; 82 maximum-programme lease identities are distinct, and a real maximum-length run resumes without new jobs. README shows one from-trackers flag value followed by positional directories. Four independent behavior-only reverts each fail 0/1 with tests retained: reserveMeta selects a foreign prefixed reservation and drifts; durableRecipeProposals adopts a foreign completed result; removing only the id-length bound reaches writes for oversize ids; restoring only the README line makes the documented-command build fail. All fixes restored; linked restored verification follows."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:52:20.236Z"}],"before_hash":"81c43e91267d14333613e5a375fd3ce5bb13534f1846b713eef210ae30d120fe","after_hash":"d9b452ecb22824d84445e4637db0a5cc49e9797130651e5c123457173370f5e8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"796635195cbbb2265ca642c5caef18e93f105cd86231d7ed7efe4925e04eb163"} +{"hash_algorithm":"sha256","ts":"2026-10-18T09:52:27.684Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/5","value":{"command":"node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T09:52:27.463Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:52:27.684Z"}],"before_hash":"d9b452ecb22824d84445e4637db0a5cc49e9797130651e5c123457173370f5e8","after_hash":"553e7961423d6c0778fe38f37eab2ffb5c7be230549c8f8ede2a69dd917c5b9b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"da0e575821396526a85d56b0b67fb5a24fbf72e0357ec50ac703a175b68ba5ea"} +{"hash_algorithm":"sha256","ts":"2026-10-18T09:58:26.605Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/29","value":{"created_at":"2026-10-18T09:58:26.605Z","author":"codex-agent","text":"Restored linked review command passed 6/6, zero failures/cancellations/skips, through pm test --run --progress. It covers canonical reservation/proposal collisions and envelope corruption, the maximum-length real programme plus idempotent resume, README-driven dataset construction, existing real decision-model fallback/replay, and SDK case-folded budget accounting. Build, test typecheck, lint, duplication and docstring gates pass. Running both full release commands with isolated HOME and global/system Git configuration before push; previous live scores and gate thresholds are retained."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:58:26.605Z"}],"before_hash":"553e7961423d6c0778fe38f37eab2ffb5c7be230549c8f8ede2a69dd917c5b9b","after_hash":"a6880fd6d904454a93737cdf3470c714d99fc6eeb84bacc187b7828ec6491a01","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a0119b18833bc233e89fc94e9271de9198b96c12c4d55dc81347e65f1ff19aba"} +{"hash_algorithm":"sha256","ts":"2026-10-18T10:17:13.734Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/30","value":{"created_at":"2026-10-18T10:17:13.734Z","author":"codex-agent","text":"The duplicate local npm run used Node 26, isolated HOME/Git identity and a memory-backed scratch area. It was deliberately interrupted while still passing corruption/continuation cases because shared-host execution was substantially slower than the existing complete CI runs. Its log is retained as incomplete, with no full-gate passing claim. Complete npm release:check on Node 22/26 and Bun release:check will run on the pushed head in the existing isolated CI matrix at unchanged thresholds. Focused linked verification remains 6/6 and four behavior-only reverts remain 0/1 each. No live-data rerun or statistical changes are needed for these receipt/lease/doc fixes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:17:13.734Z"}],"before_hash":"a6880fd6d904454a93737cdf3470c714d99fc6eeb84bacc187b7828ec6491a01","after_hash":"29767daf496e08d582d78719e95a89003ddd9898c291c614ee7c7dd744cbf2c1","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d7747dcc488b6eb62ec6e550f524cae90539f1a49e472b69576068b8631bc3bb"} diff --git a/README.md b/README.md index 84b6a105..783d7213 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,7 @@ tracker learner does not beat that baseline; the committed signal sanity case proves that real gain can promote under the same gate. [The meta-recursive contract](docs/meta-recursive.md) documents the data boundary, confidence assumptions, idempotent resume and measured real-data acceptance. Start with [the bounded programme](examples/meta-trackers.json) and -`pm rl dataset build --from-trackers --output `. +`pm rl dataset build --from-trackers --output `. The current pm-rl runtime **executes, tracks and gates** a bounded numerical loop: a generation collects trajectories, the built-in bandit trainer produces a successor, and the successor collects the next generation's diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 0b971fcb..4105775c 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -24,9 +24,16 @@ not demonstrate language-model training on tracker text. `pm rl meta run --file examples/meta-trackers.json --dataset --approval ` executes or resumes the same programme. Programme ids use lowercase letters or -digits separated by single hyphens; noncanonical ids refuse before any write. +digits separated by single hyphens, with at most 20 characters; invalid ids refuse +before any read or write. The longest inner suffix is `-initial` (eight characters), +so every outer and inner controller identity fits the existing 28-character lease +segment without truncation or collision. Retained reservation identities are compared using the SDK's case folding, so -an older uppercase spelling cannot hide an allocation. Its initial recipe +an older uppercase spelling cannot hide an allocation. Own reservation and model +proposal receipts use canonical SDK lookups, never suffix scans. Both require +Decision type and their exact envelope id; unrelated programmes cannot shadow or +supply a receipt. Proposal bindings remain independent of programme id, while +identity-less legacy attempt records fail closed. Its initial recipe is a versioned content-addressed artifact. Numeric domains cover learning rate, inner steps, batch, temperature and correct/incorrect reward weights. Categorical domains cover balanced/all selection and forward/reverse curriculum. Steps bound @@ -175,14 +182,15 @@ predictions, and full disagreement. ## Release verification -The [complete CI run](https://github.com/unbraind/pm-rl/pull/84/checks) +The [preceding CI run](https://github.com/unbraind/pm-rl/actions/runs/39110114926) executes `npm run release:check` on Node 22 and 26 and `bun run release:check` on Node 26 with isolated HOME and global/system Git configuration. Each passes 613/613 tests, zero failures/skips, 100% statements/lines/branches/functions over all 35 declared sources, 295 documented declarations, and zero duplicate clones or production audit findings. Thresholds, dependency pins and release approval are unchanged. The live evidence names the measured production source commit; -later receipt updates do not change the measured production source. +subsequent receipt-identity and id-length validation fixes preserve training and +scoring behavior; the live receipt retains its exact measured source head. The real Compose resource faults are explicit: the deadline worker publishes real LM progress then pauses past its unchanged 15-second limit; the memory @@ -195,7 +203,14 @@ resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. A separate local full-suite attempt hit the unchanged 300-second HTTP crash-drill deadline under host load and was retained as failed evidence. The required complete -commands pass in CI. External review is incomplete: CodeRabbit skips automatic -review under its star policy, Greptile reports an expired trial, Sourcery skips -and Cubic is neutral. Those states provide no approval. The PR remains unmerged, -work items remain in progress, and the orchestrator owns closure. +commands pass in CI. CodeRabbit's review of `030874d` identified three findings: suffix-based own +receipt lookup, unbounded programme ids colliding in the lease namespace, and +ambiguous README argument syntax. This round replaces own-receipt suffix scans +with canonical SDK reads and validates Decision type and body identity, caps +programme ids at 20 characters, and executes the corrected README command in a +regression test. Four independent behavior-only reverts fail with those tests +retained; restoring the fixes passes. Unreadable receipt evidence propagates, +and legacy proposal attempts without an identity refuse. Proposal bindings and +statistical gates are unchanged. Review threads stay unresolved for reviewer +verification. The PR remains unmerged, work items stay open for the orchestrator, +and no final-head review approval is claimed. diff --git a/meta.ts b/meta.ts index 65bf64a7..ee6344c5 100644 --- a/meta.ts +++ b/meta.ts @@ -1,7 +1,7 @@ /** Durable recipe search over sealed tracker compartments, using the existing trainer and promotion gate. */ import assert from "node:assert/strict"; import type { PmClient } from "@unbrained/pm-cli/sdk/core"; -import { certifyCompleteListResult } from "@unbrained/pm-cli/sdk/runtime"; +import { certifyCompleteListResult, EXIT_CODE, isPmCliExpectedError } from "@unbrained/pm-cli/sdk/runtime"; import { hashJson, commitProcessTransaction, readCompleteLoopItem, withRlController, type JsonValue, type RlDurableStep } from "./index.ts"; import { openTrackerEnvironment } from "./tracker-environment.ts"; import { parseProcessAdapter, type ProcessAdapter, type ProcessCoordinates } from "./process.ts"; @@ -102,6 +102,15 @@ export function metaReservation(body: string): { id: string; approval: string; c } catch { return null; } } +/** Read only the SDK-canonical receipt identity; unreadable evidence never becomes an absent reservation or intent. */ +async function readMetaReceipt(client: PmClient, key: string) { + try { return await readCompleteLoopItem(client, key); } + catch (error: unknown) { + if (isPmCliExpectedError(error) && error.exitCode === EXIT_CODE.NOT_FOUND) return null; + throw error; + } +} + /** Atomically hold worst-case search allowances once; interrupted programmes retain their reservation. */ async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, request: MetaRequest, binding: string): Promise { const { config } = request; @@ -110,10 +119,10 @@ async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, re const key = `${request.id}-reservation`; await commitProcessTransaction({ ...coordinates, transactionId: `${key}-reserve`, steps: [{ id: "reserve", async inspect() { - const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); - const previous = items.items.find((item) => item.type === "Decision" && (item.id === key || item.id.endsWith(`-${key}`))); - if (previous === undefined) return { state: "pending" }; - const record = JSON.parse(String((await readCompleteLoopItem(client, previous.id)).item.body)) as { format: string; id: string; binding: string; approval: string; charge: JsonValue }; + const previous = await readMetaReceipt(client, key); + if (previous === null) return { state: "pending" }; + assert.equal(previous.item.type, "Decision", "meta_reservation_drift"); + const record = JSON.parse(String(previous.item.body)) as { format: string; id: string; binding: string; approval: string; charge: JsonValue }; assert.equal(record.binding, binding, "meta_reservation_drift"); assert.equal(record.format, "pm-rl/meta-reservation/1", "meta_reservation_drift"); assert.equal(record.id, key, "meta_reservation_drift"); @@ -198,10 +207,11 @@ export async function durableRecipeProposals(client: PmClient, id: string, reque if (request.proposer === "seeded") return proposeRecipes(request, incumbent, generation, signal); const key = `${id}-m${generation}-proposal-attempt`; const binding = hashJson({ config: request.config as unknown as JsonValue, incumbent: incumbent.digest, generation, endpoint: request.decisionEndpoint ?? "http://127.0.0.1:11434" }); - const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); - const previous = items.items.find((item) => item.type === "Decision" && (item.id === key || item.id.endsWith(`-${key}`))); - if (previous !== undefined) { - const record = JSON.parse(String((await readCompleteLoopItem(client, previous.id)).item.body)) as { binding: string; state: string; result: { recipes: Recipe[]; proposer: string }; digest: string }; + const previous = await readMetaReceipt(client, key); + if (previous !== null) { + assert.equal(previous.item.type, "Decision", "meta_proposal_drift"); + const record = JSON.parse(String(previous.item.body)) as { id: string; binding: string; state: string; result: { recipes: Recipe[]; proposer: string }; digest: string }; + assert.equal(record.id, key, "meta_proposal_drift"); assert.equal(record.binding, binding, "meta_proposal_drift"); if (record.state === "complete") { assert.equal(hashJson(record.result as unknown as JsonValue), record.digest, "meta_proposal_receipt"); @@ -211,15 +221,15 @@ export async function durableRecipeProposals(client: PmClient, id: string, reque assert.equal(record.state, "intent", "meta_proposal_state"); return { recipes: seededRecipes(incumbent, request.config.seed, generation, request.config.candidates), proposer: "seeded:unresolved-model-attempt" }; } - await client.create({ id: key, type: "Decision", title: "Bounded local recipe inference intent", body: JSON.stringify({ binding, state: "intent" }) }); + await client.create({ id: key, type: "Decision", title: "Bounded local recipe inference intent", body: JSON.stringify({ id: key, binding, state: "intent" }) }); const result = await proposeRecipes(request, incumbent, generation, signal); - await client.update(key, { body: JSON.stringify({ binding, state: "complete", result, digest: hashJson(result as unknown as JsonValue) }) }); + await client.update(key, { body: JSON.stringify({ id: key, binding, state: "complete", result, digest: hashJson(result as unknown as JsonValue) }) }); return result; } /** Search and promote recipes with one shared approval; completion receipts adopt inner jobs after interruption. */ export async function runRlMeta(client: PmClient, coordinates: ProcessCoordinates, request: MetaRequest): Promise { - assert.match(request.id, /^[a-z0-9]+(?:-[a-z0-9]+)*$/, "meta_programme_id"); + assert.ok(/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(request.id) && request.id.length <= 20, "meta_programme_id"); const config = parseMetaConfig(request.config); assert.ok(request.proposer === "seeded" || request.proposer === "decision-model", "meta_proposer"); const signal = request.signal === undefined ? AbortSignal.timeout(config.timeout_ms) : AbortSignal.any([request.signal, AbortSignal.timeout(config.timeout_ms)]); diff --git a/test/meta.test.ts b/test/meta.test.ts index 7904c81a..ab12561e 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -8,7 +8,7 @@ import { join } from "node:path"; import { test } from "node:test"; import { createExtensionTestHarness } from "@unbrained/pm-cli/sdk/testing"; import { certifyCompleteListResult } from "@unbrained/pm-cli/sdk/runtime"; -import extension, { hashJson, withRlController, type JsonValue, type RlCommandResult } from "../index.ts"; +import extension, { hashJson, withRlController, type JsonValue, type RlCommandResult, loopLeaseLockId } from "../index.ts"; import { compareRecipes, durableRecipeProposals, metaReservation, parseMetaConfig, proposeRecipes, recipeExamples, recipeSuccessor, runRlMeta, scoreTrackerPolicy, type MetaConfig, type MetaRequest } from "../meta.ts"; import { INITIAL_RECIPE, recipeArtifact, seededRecipes } from "../recipe.ts"; import { banditCheckpoint } from "../bandit.ts"; @@ -180,6 +180,89 @@ test("a genuinely better recipe clears the unchanged gate and becomes the next m assert.ok(report.final_test.after.mean > report.final_test.diagnostics.majority_class.mean); }); +test("canonical reservation lookup ignores another programme's suffixed receipt and rejects wrong types", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); + const foreign = await w.client.create({ id: "a-victim-reservation", type: "Decision", title: "Other programme reservation", body: JSON.stringify({ + format: "pm-rl/meta-reservation/1", id: "a-victim-reservation", binding: "other-programme", approval: w.approval, + charge: { training_samples: 0, proposal_calls: 0, recipe_promotions: 0 }, + }) }); + const foreignBody = String((await w.client.get(foreign.item.id)).item.body); + const request = { ...requestFor(w, "victim", { ...metaConfig, meta_generations: 1, candidates: 1 }), + onStep(key: string) { if (key === "programme") throw new Error("canonical reservation committed"); } }; + await assert.rejects(runRlMeta(w.client, w.coordinates, request), /canonical reservation committed/); + const own = await w.client.get("victim-reservation"); + assert.equal((JSON.parse(String(own.item.body)) as { id: string }).id, "victim-reservation"); + await assert.rejects(runRlMeta(w.client, w.coordinates, request), /canonical reservation committed/); + assert.equal(String((await w.client.get(own.item.id)).item.body), String(own.item.body)); + assert.equal(String((await w.client.get(foreign.item.id)).item.body), foreignBody); + await w.client.create({ id: "wrong-reservation", type: "Task", title: "Invalid reservation type", body: own.item.body }); + await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "wrong")), /meta_reservation_drift/); +}); + +test("canonical proposal lookup ignores matching foreign bindings and refuses damaged own envelopes", async () => { + const w = await metaWorkspace(); const signal = new AbortController().signal; + const request = { config: metaConfig, proposer: "decision-model" as const, decisionEndpoint: "http://127.0.0.1:1" }; + const binding = hashJson({ config: request.config as unknown as JsonValue, incumbent: INITIAL_RECIPE.digest, generation: 1, endpoint: request.decisionEndpoint }); + const result = { recipes: seededRecipes(INITIAL_RECIPE, metaConfig.seed, 1, metaConfig.candidates), proposer: "foreign-complete" }; + const foreign = await w.client.create({ id: "a-victim-m1-proposal-attempt", type: "Decision", title: "Other programme proposal", body: JSON.stringify({ + id: "a-victim-m1-proposal-attempt", binding, state: "complete", result, digest: hashJson(result as unknown as JsonValue), + }) }); + const foreignBody = String((await w.client.get(foreign.item.id)).item.body); + const own = await durableRecipeProposals(w.client, "victim", request, INITIAL_RECIPE, 1, signal); + assert.equal(own.proposer, "seeded:model-unavailable"); + assert.deepEqual(await durableRecipeProposals(w.client, "victim", request, INITIAL_RECIPE, 1, signal), own); + assert.equal(String((await w.client.get(foreign.item.id)).item.body), foreignBody); + const item = await w.client.get("victim-m1-proposal-attempt"); const record = JSON.parse(String(item.item.body)) as Record; + assert.equal(record.id, "victim-m1-proposal-attempt"); + for (const id of ["other-m1-proposal-attempt", undefined]) { + await w.client.update(item.item.id, { body: JSON.stringify({ ...record, id }) }); + await assert.rejects(durableRecipeProposals(w.client, "victim", request, INITIAL_RECIPE, 1, signal), /meta_proposal_drift/); + } + await w.client.create({ id: "typed-m1-proposal-attempt", type: "Task", title: "Invalid proposal type", body: JSON.stringify({ ...record, id: "typed-m1-proposal-attempt" }) }); + await assert.rejects(durableRecipeProposals(w.client, "typed", request, INITIAL_RECIPE, 1, signal), /meta_proposal_drift/); + const broken = await w.client.create({ id: "broken-m1-proposal-attempt", type: "Decision", title: "Unreadable proposal record" }); + const path = join(w.coordinates.pmRoot, "decisions", `${broken.item.id}.toon`); const original = readFileSync(path, "utf8"); + try { + writeFileSync(path, "broken: [invalid\n"); + const failure: unknown = await w.client.get(broken.item.id).catch((error: unknown) => error); + assert.ok(failure instanceof Error, "damaged tracker item must fail the real SDK read"); + await assert.rejects(durableRecipeProposals(w.client, "broken", request, INITIAL_RECIPE, 1, signal), { message: failure.message }); + } finally { writeFileSync(path, original); } +}); + +test("programme id bounds prevent outer and inner lease collisions before any write", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); + for (const id of ["a".repeat(21), "a".repeat(28), "tracker-search-public-fleet-v1"]) { + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, id), + onStep() { throw new Error("oversize programme reached a write"); } }), /meta_programme_id/); + } + assert.equal(certifyCompleteListResult(await w.client.listAllComplete({ includeBody: false })).items.length, 1); + const id = "abcdefghijklmnopqrst"; + const identities = [id, `${id}-initial`, ...Array.from({ length: 10 }, (_, generation) => + Array.from({ length: 8 }, (_, candidate) => `${id}-m${generation + 1}-c${candidate}`)).flat()]; + assert.equal(new Set(identities.map(loopLeaseLockId)).size, 82, "all bounded inner leases remain distinct at the maximum accepted id length"); + const request = requestFor(w, id, { ...metaConfig, meta_generations: 1, candidates: 1 }); + const report = await runRlMeta(w.client, w.coordinates, request); const jobs = await listProcessJobs(w.client); + assert.equal(report.generations.length, 1); + assert.deepEqual(await runRlMeta(w.client, w.coordinates, request), report); + assert.deepEqual(await listProcessJobs(w.client), jobs); +}); + +test("README dataset command builds from its first flag value and positional tracker directories", async () => { + const w = await metaWorkspace(); const harness = await createExtensionTestHarness(extension, { name: "pm-rl", capabilities: ["commands", "hooks", "schema"] }); + const readme = readFileSync(new URL("../README.md", import.meta.url), "utf8"); + const usage = /`pm rl dataset build ([^`]+)`/.exec(readme); assert.ok(usage !== null); + await withTrackerSources(async (source) => { + const placeholders: Record = { "": [source.directories[0]], "": source.directories.slice(1), "": [join(source.root, "documented-dataset")] }; + const words = usage[1].replace(/\.$/, "").split(/\s+/).flatMap((word) => placeholders[word] ?? [word]); + const trackers = words.indexOf("--from-trackers"); const output = words.indexOf("--output"); + const result = await harness.runCommand({ command: "rl dataset build", pmRoot: w.coordinates.pmRoot, + args: words.slice(trackers + 2, output), options: { fromTrackers: words[trackers + 1], output: words[output + 1] } }); + assert.equal(result.handled, true, result.errorMessage ?? "documented command must build a dataset"); + assert.equal((result.result as RlCommandResult).action, "rl-dataset-build"); + }); +}); + test("an interrupted atomic search reservation is retained once, including drift refusal on resume", { timeout: 600_000 }, async () => { const w = await metaWorkspace(); const request = requestFor(w, "transaction", { ...metaConfig, meta_generations: 1, candidates: 1 }); await assert.rejects(runRlMeta(w.client, { ...w.coordinates, onTransition(context) { if (context.transition === "step_applied") throw new Error("reservation interrupted"); } }, request), /reservation interrupted/); From 2820234215213502be6583ba77f7c4a23cc2d51f Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 12:33:13 +0200 Subject: [PATCH 11/24] test: keep budget fixture ids within the meta programme bound --- .agents/pm/features/pm-rl-meta.toon | 9 ++++++--- .agents/pm/history/pm-rl-meta.jsonl | 3 +++ docs/meta-recursive.md | 3 +-- test/meta.test.ts | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 3fe9f724..4737fa70 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T10:17:13.734Z" +updated_at: "2026-10-18T10:33:04.727Z" assignee: codex-agent claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[31]{created_at,author,text}: +comments[33]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -44,6 +44,8 @@ comments[31]{created_at,author,text}: "2026-10-18T09:52:20.236Z",codex-agent,"All three review findings are fixed. Reservation and proposal receipt reads use the SDK-canonical key, validate Decision type and exact body id, treat only expected NOT_FOUND as absence, and propagate unreadable evidence. Proposal intent/completion envelopes now persist id without changing the binding. Programme ids are capped at 20: adding the longest eight-character inner suffix stays within the existing 28-character lease segment; 82 maximum-programme lease identities are distinct, and a real maximum-length run resumes without new jobs. README shows one from-trackers flag value followed by positional directories. Four independent behavior-only reverts each fail 0/1 with tests retained: reserveMeta selects a foreign prefixed reservation and drifts; durableRecipeProposals adopts a foreign completed result; removing only the id-length bound reaches writes for oversize ids; restoring only the README line makes the documented-command build fail. All fixes restored; linked restored verification follows." "2026-10-18T09:58:26.605Z",codex-agent,"Restored linked review command passed 6/6, zero failures/cancellations/skips, through pm test --run --progress. It covers canonical reservation/proposal collisions and envelope corruption, the maximum-length real programme plus idempotent resume, README-driven dataset construction, existing real decision-model fallback/replay, and SDK case-folded budget accounting. Build, test typecheck, lint, duplication and docstring gates pass. Running both full release commands with isolated HOME and global/system Git configuration before push; previous live scores and gate thresholds are retained." "2026-10-18T10:17:13.734Z",codex-agent,"The duplicate local npm run used Node 26, isolated HOME/Git identity and a memory-backed scratch area. It was deliberately interrupted while still passing corruption/continuation cases because shared-host execution was substantially slower than the existing complete CI runs. Its log is retained as incomplete, with no full-gate passing claim. Complete npm release:check on Node 22/26 and Bun release:check will run on the pushed head in the existing isolated CI matrix at unchanged thresholds. Focused linked verification remains 6/6 and four behavior-only reverts remain 0/1 each. No live-data rerun or statistical changes are needed for these receipt/lease/doc fixes." + "2026-10-18T10:31:06.431Z",codex-agent,"CI run 39118685929 on 54b2573 reports the same single fixture failure in npm Node 22/26 and Bun Node 26: 616/617 pass. The existing budget test generated exhaust-training-samples and exhaust-recipe-promotions, which exceed the new 20-character programme-id contract; it therefore stopped at meta_programme_id before its expected budget refusal. This early exit also left 99.89% aggregate branch coverage, so all three gates correctly failed. Shortening only these test programme names to their unique first key component preserves every original budget assertion and production guard. The focused linked command is extended to include this complete budget regression. All three review threads were acknowledged and resolved by CodeRabbit itself after code inspection; no resolution requests were made by this author, and the bot did not execute tests." + "2026-10-18T10:33:04.727Z",codex-agent,"The expanded linked review run passes 7/7, zero failures/cancellations/skips, after shortening only the budget-test programme labels. Every training-sample, proposal-call, promotion, approval-replacement, malformed-charge and pretty-body assertion remains intact. This restores execution of the previously aborted budget branches without changing production code or weakening any check. Four review revert proofs remain valid against unchanged fixed functions and README. Pushing the test-only compatibility correction for a complete rerun of both isolated release gates." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project @@ -69,13 +71,14 @@ files[24]{path,scope}: test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[6]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[7]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts",project,600,codex-agent,"2026-10-18T06:35:18.894Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T07:43:42.817Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T09:52:27.463Z",local_mutation,feat/meta-recursive-recipe-loop + "node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity|one pre-approved\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T10:31:09.686Z",local_mutation,feat/meta-recursive-recipe-loop docs[7]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 6db59fe6..ccb67eba 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -59,3 +59,6 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T09:52:27.684Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/5","value":{"command":"node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T09:52:27.463Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:52:27.684Z"}],"before_hash":"d9b452ecb22824d84445e4637db0a5cc49e9797130651e5c123457173370f5e8","after_hash":"553e7961423d6c0778fe38f37eab2ffb5c7be230549c8f8ede2a69dd917c5b9b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"da0e575821396526a85d56b0b67fb5a24fbf72e0357ec50ac703a175b68ba5ea"} {"hash_algorithm":"sha256","ts":"2026-10-18T09:58:26.605Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/29","value":{"created_at":"2026-10-18T09:58:26.605Z","author":"codex-agent","text":"Restored linked review command passed 6/6, zero failures/cancellations/skips, through pm test --run --progress. It covers canonical reservation/proposal collisions and envelope corruption, the maximum-length real programme plus idempotent resume, README-driven dataset construction, existing real decision-model fallback/replay, and SDK case-folded budget accounting. Build, test typecheck, lint, duplication and docstring gates pass. Running both full release commands with isolated HOME and global/system Git configuration before push; previous live scores and gate thresholds are retained."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T09:58:26.605Z"}],"before_hash":"553e7961423d6c0778fe38f37eab2ffb5c7be230549c8f8ede2a69dd917c5b9b","after_hash":"a6880fd6d904454a93737cdf3470c714d99fc6eeb84bacc187b7828ec6491a01","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a0119b18833bc233e89fc94e9271de9198b96c12c4d55dc81347e65f1ff19aba"} {"hash_algorithm":"sha256","ts":"2026-10-18T10:17:13.734Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/30","value":{"created_at":"2026-10-18T10:17:13.734Z","author":"codex-agent","text":"The duplicate local npm run used Node 26, isolated HOME/Git identity and a memory-backed scratch area. It was deliberately interrupted while still passing corruption/continuation cases because shared-host execution was substantially slower than the existing complete CI runs. Its log is retained as incomplete, with no full-gate passing claim. Complete npm release:check on Node 22/26 and Bun release:check will run on the pushed head in the existing isolated CI matrix at unchanged thresholds. Focused linked verification remains 6/6 and four behavior-only reverts remain 0/1 each. No live-data rerun or statistical changes are needed for these receipt/lease/doc fixes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:17:13.734Z"}],"before_hash":"a6880fd6d904454a93737cdf3470c714d99fc6eeb84bacc187b7828ec6491a01","after_hash":"29767daf496e08d582d78719e95a89003ddd9898c291c614ee7c7dd744cbf2c1","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d7747dcc488b6eb62ec6e550f524cae90539f1a49e472b69576068b8631bc3bb"} +{"hash_algorithm":"sha256","ts":"2026-10-18T10:31:06.431Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/31","value":{"created_at":"2026-10-18T10:31:06.431Z","author":"codex-agent","text":"CI run 39118685929 on 54b2573 reports the same single fixture failure in npm Node 22/26 and Bun Node 26: 616/617 pass. The existing budget test generated exhaust-training-samples and exhaust-recipe-promotions, which exceed the new 20-character programme-id contract; it therefore stopped at meta_programme_id before its expected budget refusal. This early exit also left 99.89% aggregate branch coverage, so all three gates correctly failed. Shortening only these test programme names to their unique first key component preserves every original budget assertion and production guard. The focused linked command is extended to include this complete budget regression. All three review threads were acknowledged and resolved by CodeRabbit itself after code inspection; no resolution requests were made by this author, and the bot did not execute tests."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:31:06.431Z"}],"before_hash":"29767daf496e08d582d78719e95a89003ddd9898c291c614ee7c7dd744cbf2c1","after_hash":"9b8513c644a6641e536dea2b4fbc7f53d0077f17cf08afcd7163c0ef15d71466","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a59dce9f28398a354025dfbc0b9de4b721b482a8a10fb89b080e573dc6b5c3b0"} +{"hash_algorithm":"sha256","ts":"2026-10-18T10:31:09.749Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/6","value":{"command":"node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity|one pre-approved\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T10:31:09.686Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:31:09.749Z"}],"before_hash":"9b8513c644a6641e536dea2b4fbc7f53d0077f17cf08afcd7163c0ef15d71466","after_hash":"d785992dd3d39a795db29504d45cc9f6b4827cce2eedbd01f3e0b26150c56b1b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"1d60fef892b4933532112ef6a64fdd82f1973ecf17d3118914448dddf90174e6"} +{"hash_algorithm":"sha256","ts":"2026-10-18T10:33:04.727Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/32","value":{"created_at":"2026-10-18T10:33:04.727Z","author":"codex-agent","text":"The expanded linked review run passes 7/7, zero failures/cancellations/skips, after shortening only the budget-test programme labels. Every training-sample, proposal-call, promotion, approval-replacement, malformed-charge and pretty-body assertion remains intact. This restores execution of the previously aborted budget branches without changing production code or weakening any check. Four review revert proofs remain valid against unchanged fixed functions and README. Pushing the test-only compatibility correction for a complete rerun of both isolated release gates."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:33:04.727Z"}],"before_hash":"d785992dd3d39a795db29504d45cc9f6b4827cce2eedbd01f3e0b26150c56b1b","after_hash":"7a016d82c4798d49a54b3814d0c7f73543a9bf3633e59d4a440b8c193360fc94","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"97feab5a80cc54c098b78fd1fdc023a606695c5ceab5d22ed28535be94ccdab9"} diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 4105775c..023b80a7 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -211,6 +211,5 @@ programme ids at 20 characters, and executes the corrected README command in a regression test. Four independent behavior-only reverts fail with those tests retained; restoring the fixes passes. Unreadable receipt evidence propagates, and legacy proposal attempts without an identity refuse. Proposal bindings and -statistical gates are unchanged. Review threads stay unresolved for reviewer -verification. The PR remains unmerged, work items stay open for the orchestrator, +statistical gates are unchanged. Thread resolution is left to reviewers. The PR remains unmerged, work items stay open for the orchestrator, and no final-head review approval is claimed. diff --git a/test/meta.test.ts b/test/meta.test.ts index ab12561e..27dc5cbc 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -317,7 +317,7 @@ test("one pre-approved Decision cannot be enlarged, replaced or oversubscribed, for (const key of ["training_samples", "proposal_calls", "recipe_promotions"] as const) { const spec = { ...metaSpec, meta_budget: { ...metaSpec.meta_budget, [key]: 0 } }; await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify(spec)}\n\`\`\`` }); - await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, `exhaust-${key.replaceAll("_", "-")}`), proposer: "decision-model" }), new RegExp(`meta_budget_exhausted: ${key}`)); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, `exhaust-${key.split("_")[0]}`), proposer: "decision-model" }), new RegExp(`meta_budget_exhausted: ${key}`)); } await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify(metaSpec)}\n\`\`\`` }); const request = requestFor(w, "bound", { ...metaConfig, meta_generations: 1, candidates: 1 }); From 798cfe8af45371ddec478e5b8c2e79259be0fce5 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 13:01:15 +0200 Subject: [PATCH 12/24] test: synchronize native OOM evidence before fixture exit --- .agents/pm/features/pm-rl-meta.toon | 6 +++-- .agents/pm/features/pm-rl-whrd.toon | 21 ++++++++++++--- .agents/pm/history/pm-rl-meta.jsonl | 2 ++ .agents/pm/history/pm-rl-whrd.jsonl | 5 ++++ docs/meta-recursive.md | 7 +++-- test/fixtures/lm-compose-memory.ts | 41 +++++++++++++++++++++-------- test/lm-compose.test.ts | 34 +++++++++++++++++++++--- 7 files changed, 94 insertions(+), 22 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 4737fa70..aefb6444 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T10:33:04.727Z" +updated_at: "2026-10-18T11:01:12.428Z" assignee: codex-agent claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[33]{created_at,author,text}: +comments[35]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -46,6 +46,8 @@ comments[33]{created_at,author,text}: "2026-10-18T10:17:13.734Z",codex-agent,"The duplicate local npm run used Node 26, isolated HOME/Git identity and a memory-backed scratch area. It was deliberately interrupted while still passing corruption/continuation cases because shared-host execution was substantially slower than the existing complete CI runs. Its log is retained as incomplete, with no full-gate passing claim. Complete npm release:check on Node 22/26 and Bun release:check will run on the pushed head in the existing isolated CI matrix at unchanged thresholds. Focused linked verification remains 6/6 and four behavior-only reverts remain 0/1 each. No live-data rerun or statistical changes are needed for these receipt/lease/doc fixes." "2026-10-18T10:31:06.431Z",codex-agent,"CI run 39118685929 on 54b2573 reports the same single fixture failure in npm Node 22/26 and Bun Node 26: 616/617 pass. The existing budget test generated exhaust-training-samples and exhaust-recipe-promotions, which exceed the new 20-character programme-id contract; it therefore stopped at meta_programme_id before its expected budget refusal. This early exit also left 99.89% aggregate branch coverage, so all three gates correctly failed. Shortening only these test programme names to their unique first key component preserves every original budget assertion and production guard. The focused linked command is extended to include this complete budget regression. All three review threads were acknowledged and resolved by CodeRabbit itself after code inspection; no resolution requests were made by this author, and the bot did not execute tests." "2026-10-18T10:33:04.727Z",codex-agent,"The expanded linked review run passes 7/7, zero failures/cancellations/skips, after shortening only the budget-test programme labels. Every training-sample, proposal-call, promotion, approval-replacement, malformed-charge and pretty-body assertion remains intact. This restores execution of the previously aborted budget branches without changing production code or weakening any check. Four review revert proofs remain valid against unchanged fixed functions and README. Pushing the test-only compatibility correction for a complete rerun of both isolated release gates." + "2026-10-18T10:52:06.830Z",codex-agent,"Corrected-head CI run 39119714690 now passes npm Node 22 and Bun Node 26 at 617/617 with all four coverage metrics 100%; the complete budget regression and every meta branch pass. npm Node 26 also has full meta coverage but hits an existing native-memory fault fixture intermittently: its failed trainer receipt has OOMKilled false at the strict physical-OOM assertion. No meta assertion fails. Investigating and synchronizing the fault evidence rather than retrying until green or weakening the memory assertion." + "2026-10-18T11:01:12.427Z",codex-agent,"The native-memory fixture correction passes both direct and restored PM-linked real-container verification 1/1, zero failures/skips. A fixture-only behavioral revert fails 0/1 at the missing durable child-death handshake; restoring it passes. The test observes an actual kernel SIGKILL and Docker OOMKilled=true before releasing an idle failed supervisor, retaining original memory/time caps and every existing refusal assertion. Build:test, lint, duplicates and documentation checks pass: 35 source files, 295 documented declarations. Two release variants already pass 617/617 on 2820234; the complete three-variant isolated release matrix will rerun on this fixture correction. Registry currently reports CLI 2026.10.18; pinned SDK remains 2026.10.13 as required. No live retraining or statistical changes were needed." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/features/pm-rl-whrd.toon b/.agents/pm/features/pm-rl-whrd.toon index fba85ef1..38790405 100644 --- a/.agents/pm/features/pm-rl-whrd.toon +++ b/.agents/pm/features/pm-rl-whrd.toon @@ -6,11 +6,13 @@ status: in_progress priority: 2 tags[3]: execution,llm-adapter,recursive-training created_at: "2026-10-15T22:07:13.392Z" -updated_at: "2026-10-18T07:03:27.069Z" +updated_at: "2026-10-18T11:00:28.454Z" +assignee: codex-agent +claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two real generations with successor collection; SIGKILL recovery, cancellation, corrupt checkpoint and limit refusals, one-launch contention; behavioural revert proofs and unchanged npm and Bun release gates." parent: pm-rl-apvf -comments[27]{created_at,author,text}: +comments[29]{created_at,author,text}: "2026-10-15T22:07:43.111Z",codex-agent,"Design: extend the existing process contract with a typed LM payload and checkpoint validator; share owner fences, atomic reservation, staged adoption, cancellation and settlement. Keep held-out examples in the controller. Bind immutable image, memory and CPU ceilings into programme and job identity; send only frozen weights, source adapter, training strings and collected rewards to a networkless non-root container. Add real recursive generations and crash/cancellation/limit/contention drills, then behavioural revert proofs and unchanged release gates." "2026-10-15T22:16:06.750Z",codex-agent,"First real Compose evidence: generation 1 checkpoint 058aa3d2c08438abd18cf0e9b455aca99ddb95492de852201c55c79a0672130d -> 37e503748a170be32e1d506997b6c0cc5c9ee256b24ab01fb49cf0564da07b4c; held-out sampled reward 0.183854, six steps, 1152 target tokens, observed wall 5567 ms, fit CPU 820 ms, peak RSS 138629120 bytes, retained staging 88930 bytes. Generation 2 collected with that promoted digest and trained -> 086f78992283cba37929321abe3961ca6132a52c332bf8a8387a52f22141cbdb; reward 0.292396, six steps, 1152 tokens, wall 5654 ms, CPU 803 ms, peak RSS 143323136 bytes, staging 92364 bytes. Both promoted through the existing gate. Real controller SIGKILL after completion before receipt commit recovered the same checkpoint and original reservation with one launch. Mid-fit cancellation retained input/events and process_cancelled. Full drills and coverage verification continue. The first linked run reached its default 120-second timeout; rerun will explicitly allow the complete integration duration." "2026-10-15T22:24:09.789Z",codex-agent,"Validated linked run: pm test pm-rl-whrd --run --progress --timeout 900 passed 8/8, zero failures/skips/cancellations/todo. Real kernel memory drill retained partial allocation evidence and daemon oom_killed=true at 201326592 bytes; the time drill began the real 1000-step fit before exceeding its 15000 ms allowance. Both refused promotion and successor collection. Two-generation execution took 54134.161 ms; independent verification/replay/status took 4470.981 ms. Canonical hashes and held-out objectives match the first measurement. Final fit resources: generation 1 wall 4297 ms, CPU 713 ms, RSS 138207232 bytes, staging 89057 bytes; generation 2 wall 4266 ms, CPU 759 ms, RSS 144183296 bytes, staging 92509 bytes; both six steps and 1152 target tokens. Daemon receipts verify memory=268435456, CPU=1, no network and non-root user. Existing Compose barrier variability is tracked in pm-rl-8nev. Revert proofs and complete release gates remain in progress." @@ -38,6 +40,8 @@ comments[27]{created_at,author,text}: "2026-10-18T06:19:59.564Z",codex-agent,"Current meta-feature CI exposed a timing-dependent existing fault drill: the Node 26 job observed two collection Runs instead of one in the corrupt/memory/time test, while every authored source reported 100% lines/branches/functions. The time case assumed 1000 real LM fit steps necessarily exceeded 15000 ms; that assumption depends on runner speed. The correction selects a time-only fixture that enters the actual packaged LM trainer, publishes its genuine zero-step progress, retains a barrier marker and blocks before numerical fit until the unchanged process deadline terminates the container. Corrupt and memory modes, the 15000 ms allowance, every existing failure/no-successor/cleanup/resume assertion, production training and promotion criteria remain unchanged. Focused physical verification and full gates are pending. The earlier merged acceptance audit remains historical evidence, not a passing result for this new attempt." "2026-10-18T06:39:11.323Z",codex-agent,"Resource-drill stabilization verified physically: the deadline fixture forwards the genuine packaged LM zero-step progress and blocks before fit; the unchanged 15000 ms guard kills it. The separate minimal allocator records its V8 heap ceiling above the unchanged 201326592-byte cgroup cap, then causes a native Docker OOM; the OOMKilled assertion is preserved. Every existing failed/settled/no-completion/one-Run/no-promoted-generation/retained-input/event/container-removal/resume-refusal assertion remains. Focused restored test passes 1/1. In an isolated source snapshot, reverting only memory-worker dispatch fails 0/1 with Missing expected rejection for memory; reverting only the time barrier fails 0/1 with missing time-barrier evidence; restoring both passes 1/1. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. The PM-linked run also passes 1/1, zero skips. Build:test, lint and static publish attestation pass. Full CI must rerun; leave in progress for orchestrator verification." "2026-10-18T07:03:16.944Z",codex-agent,"Final current validation: CI run https://github.com/unbraind/pm-rl/actions/runs/39104826277 on 445b232 passes all three complete gates (npm Node 22, npm Node 26, Bun Node 26), 612/612 each, zero skips, all four coverage metrics 100% across 35 required sources and 295 documented declarations. The real corruption/native-OOM/15-second-deadline refusal drill passes with every original failure, no-successor, cleanup and resume assertion retained. Its two fault-guard reverts fail 0/1 each; restored physical and linked verification passes 1/1. The original merged-PR acceptance audit remains Met, now supplemented by stable current fault injection. No production trainer or promotion changes, pin bump, larger physical allowance or release enablement. Leave in progress for orchestrator closure; release the claim after these receipts." + "2026-10-18T10:52:07.652Z",codex-agent,"Review-round full CI exposed a physical-memory fault race: one Node 26 runner recorded OOMKilled false, while Node 22 and Bun runners passed the same strict native-OOM case. The current minimal allocator exits as soon as the kernel kills its PID 1. Docker records OOM notifications separately from task exit; terminal cleanup can observe incomplete daemon OOM evidence. The fixture will keep a minimal parent alive after a native memory-exhausting child is killed and release that parent only after the test observes Docker's real OOM flag. Preserve the 192 MiB cap, 1 GiB V8 ceiling, original deadlines, refusal/no-successor/settlement/cleanup/resume assertions; no production trainer or promotion-gate change." + "2026-10-18T11:00:28.454Z",codex-agent,"The Node 26 CI failure exposed a native-memory fixture race: the daemon processes kernel OOM and init exit independently. The test now keeps an idle supervisor alive while its memory-exhausting child is genuinely OOM-killed, observes Docker OOMKilled=true within the existing bounded barrier, then releases the failed supervisor. The child prefers itself via its own positive OOM score adjustment; no simulated kill is used. The physical cap remains 192 MiB, V8 ceiling remains 1 GiB, wall allowance remains 15 seconds, and all refusal, receipt, no-successor, cleanup and resume assertions remain. Focused real-container verification passed 1/1. Restoring only the old memory fixture with the new test retained fails 0/1 at the missing kernel-event handshake; the fixed fixture is restored. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. Production trainer and promotion code are unchanged." files[21]{path,scope}: .dockerignore,project compose.ts,project @@ -60,7 +64,7 @@ files[21]{path,scope}: test/fixtures/lm-compose.Dockerfile,project test/fixtures/process-controller.ts,project test/lm-compose.test.ts,project -tests[4]: +tests[5]: - command: node --test test/lm-compose.test.ts scope: project provenance: @@ -90,8 +94,17 @@ tests[4]: created_at: "2026-10-16T04:27:20.119Z" source_kind: local_mutation source_ref: feat/lm-compose-trainer -docs[4]{path,scope}: + - command: "node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts" + scope: project + timeout_seconds: 600 + provenance: + author: codex-agent + created_at: "2026-10-18T11:00:25.569Z" + source_kind: local_mutation + source_ref: feat/meta-recursive-recipe-loop +docs[5]{path,scope}: docs/lm-adapter.md,project + docs/meta-recursive.md,project docs/process-trainer.md,project README.md,project RECURSIVE_TRAINING.md,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index ccb67eba..34a2f679 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -62,3 +62,5 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T10:31:06.431Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/31","value":{"created_at":"2026-10-18T10:31:06.431Z","author":"codex-agent","text":"CI run 39118685929 on 54b2573 reports the same single fixture failure in npm Node 22/26 and Bun Node 26: 616/617 pass. The existing budget test generated exhaust-training-samples and exhaust-recipe-promotions, which exceed the new 20-character programme-id contract; it therefore stopped at meta_programme_id before its expected budget refusal. This early exit also left 99.89% aggregate branch coverage, so all three gates correctly failed. Shortening only these test programme names to their unique first key component preserves every original budget assertion and production guard. The focused linked command is extended to include this complete budget regression. All three review threads were acknowledged and resolved by CodeRabbit itself after code inspection; no resolution requests were made by this author, and the bot did not execute tests."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:31:06.431Z"}],"before_hash":"29767daf496e08d582d78719e95a89003ddd9898c291c614ee7c7dd744cbf2c1","after_hash":"9b8513c644a6641e536dea2b4fbc7f53d0077f17cf08afcd7163c0ef15d71466","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a59dce9f28398a354025dfbc0b9de4b721b482a8a10fb89b080e573dc6b5c3b0"} {"hash_algorithm":"sha256","ts":"2026-10-18T10:31:09.749Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/6","value":{"command":"node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity|one pre-approved\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T10:31:09.686Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:31:09.749Z"}],"before_hash":"9b8513c644a6641e536dea2b4fbc7f53d0077f17cf08afcd7163c0ef15d71466","after_hash":"d785992dd3d39a795db29504d45cc9f6b4827cce2eedbd01f3e0b26150c56b1b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"1d60fef892b4933532112ef6a64fdd82f1973ecf17d3118914448dddf90174e6"} {"hash_algorithm":"sha256","ts":"2026-10-18T10:33:04.727Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/32","value":{"created_at":"2026-10-18T10:33:04.727Z","author":"codex-agent","text":"The expanded linked review run passes 7/7, zero failures/cancellations/skips, after shortening only the budget-test programme labels. Every training-sample, proposal-call, promotion, approval-replacement, malformed-charge and pretty-body assertion remains intact. This restores execution of the previously aborted budget branches without changing production code or weakening any check. Four review revert proofs remain valid against unchanged fixed functions and README. Pushing the test-only compatibility correction for a complete rerun of both isolated release gates."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:33:04.727Z"}],"before_hash":"d785992dd3d39a795db29504d45cc9f6b4827cce2eedbd01f3e0b26150c56b1b","after_hash":"7a016d82c4798d49a54b3814d0c7f73543a9bf3633e59d4a440b8c193360fc94","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"97feab5a80cc54c098b78fd1fdc023a606695c5ceab5d22ed28535be94ccdab9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T10:52:06.830Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/33","value":{"created_at":"2026-10-18T10:52:06.830Z","author":"codex-agent","text":"Corrected-head CI run 39119714690 now passes npm Node 22 and Bun Node 26 at 617/617 with all four coverage metrics 100%; the complete budget regression and every meta branch pass. npm Node 26 also has full meta coverage but hits an existing native-memory fault fixture intermittently: its failed trainer receipt has OOMKilled false at the strict physical-OOM assertion. No meta assertion fails. Investigating and synchronizing the fault evidence rather than retrying until green or weakening the memory assertion."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:52:06.830Z"}],"before_hash":"7a016d82c4798d49a54b3814d0c7f73543a9bf3633e59d4a440b8c193360fc94","after_hash":"4860b7293a11e98761883450d4e5d2d4cc1416416ead4d4569fdcdfa6ac0d9ec","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"13064a9b0dbeef1346c4f3cbc9411655eca9ab3eaf65a0e9911da39811221f6c"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:01:12.428Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/34","value":{"created_at":"2026-10-18T11:01:12.427Z","author":"codex-agent","text":"The native-memory fixture correction passes both direct and restored PM-linked real-container verification 1/1, zero failures/skips. A fixture-only behavioral revert fails 0/1 at the missing durable child-death handshake; restoring it passes. The test observes an actual kernel SIGKILL and Docker OOMKilled=true before releasing an idle failed supervisor, retaining original memory/time caps and every existing refusal assertion. Build:test, lint, duplicates and documentation checks pass: 35 source files, 295 documented declarations. Two release variants already pass 617/617 on 2820234; the complete three-variant isolated release matrix will rerun on this fixture correction. Registry currently reports CLI 2026.10.18; pinned SDK remains 2026.10.13 as required. No live retraining or statistical changes were needed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:01:12.428Z"}],"before_hash":"4860b7293a11e98761883450d4e5d2d4cc1416416ead4d4569fdcdfa6ac0d9ec","after_hash":"bf643730b549790bb66967fee821751b4c3302accc420aaeb924b630013a8cda","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"3118e07fdaf40e6bf9aa3ac7f5a76d54e771cb701fd1b024fe279d09110bd63d"} diff --git a/.agents/pm/history/pm-rl-whrd.jsonl b/.agents/pm/history/pm-rl-whrd.jsonl index fc0dac4a..9cc372e0 100644 --- a/.agents/pm/history/pm-rl-whrd.jsonl +++ b/.agents/pm/history/pm-rl-whrd.jsonl @@ -48,3 +48,8 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T06:39:11.323Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/25","value":{"created_at":"2026-10-18T06:39:11.323Z","author":"codex-agent","text":"Resource-drill stabilization verified physically: the deadline fixture forwards the genuine packaged LM zero-step progress and blocks before fit; the unchanged 15000 ms guard kills it. The separate minimal allocator records its V8 heap ceiling above the unchanged 201326592-byte cgroup cap, then causes a native Docker OOM; the OOMKilled assertion is preserved. Every existing failed/settled/no-completion/one-Run/no-promoted-generation/retained-input/event/container-removal/resume-refusal assertion remains. Focused restored test passes 1/1. In an isolated source snapshot, reverting only memory-worker dispatch fails 0/1 with Missing expected rejection for memory; reverting only the time barrier fails 0/1 with missing time-barrier evidence; restoring both passes 1/1. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. The PM-linked run also passes 1/1, zero skips. Build:test, lint and static publish attestation pass. Full CI must rerun; leave in progress for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T06:39:11.323Z"}],"before_hash":"3481c36d0d5ca47685b7d688f30808812caae8ae9e6d30bbbffbc11be5067bc5","after_hash":"4c39db89407361b3db5eb1fd84fce6b4604158cbc00ce5670b7dbddeb4f62182","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e2b9c53994775da7fc80226564c33960e8ceb07bfe80fcf89ec3fa16c09721ae"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:03:16.946Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/26","value":{"created_at":"2026-10-18T07:03:16.944Z","author":"codex-agent","text":"Final current validation: CI run https://github.com/unbraind/pm-rl/actions/runs/39104826277 on 445b232 passes all three complete gates (npm Node 22, npm Node 26, Bun Node 26), 612/612 each, zero skips, all four coverage metrics 100% across 35 required sources and 295 documented declarations. The real corruption/native-OOM/15-second-deadline refusal drill passes with every original failure, no-successor, cleanup and resume assertion retained. Its two fault-guard reverts fail 0/1 each; restored physical and linked verification passes 1/1. The original merged-PR acceptance audit remains Met, now supplemented by stable current fault injection. No production trainer or promotion changes, pin bump, larger physical allowance or release enablement. Leave in progress for orchestrator closure; release the claim after these receipts."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:03:16.946Z"}],"before_hash":"4c39db89407361b3db5eb1fd84fce6b4604158cbc00ce5670b7dbddeb4f62182","after_hash":"8cfda477df504679c0dd958ba96bfed41e962194acdd920dfbdf85203b1ba184","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"741d24fdbeb6bbea9f85fddc07b5733e9b260321e013d48f69f3a871b4b56155"} {"hash_algorithm":"sha256","ts":"2026-10-18T07:03:27.069Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T07:03:27.069Z"}],"before_hash":"8cfda477df504679c0dd958ba96bfed41e962194acdd920dfbdf85203b1ba184","after_hash":"deb12c248bf96d088c72596e030874315cf497d5872f92235db7072d8f41f6b0","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"509ac1b633cef7411b2f2d08fd891597578298f06e1bf728a166406a5457b00f"} +{"hash_algorithm":"sha256","ts":"2026-10-18T10:52:06.096Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:52:06.096Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"deb12c248bf96d088c72596e030874315cf497d5872f92235db7072d8f41f6b0","after_hash":"c3604f90e82634b162615bbd002aa4d4583d9022d09d08eb92b75b05013e4a54","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"bef6a5a0fb935c1e7aca05587c851df863f8cb9142b3e9bd89b33793de9c6fb1"} +{"hash_algorithm":"sha256","ts":"2026-10-18T10:52:07.652Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/27","value":{"created_at":"2026-10-18T10:52:07.652Z","author":"codex-agent","text":"Review-round full CI exposed a physical-memory fault race: one Node 26 runner recorded OOMKilled false, while Node 22 and Bun runners passed the same strict native-OOM case. The current minimal allocator exits as soon as the kernel kills its PID 1. Docker records OOM notifications separately from task exit; terminal cleanup can observe incomplete daemon OOM evidence. The fixture will keep a minimal parent alive after a native memory-exhausting child is killed and release that parent only after the test observes Docker's real OOM flag. Preserve the 192 MiB cap, 1 GiB V8 ceiling, original deadlines, refusal/no-successor/settlement/cleanup/resume assertions; no production trainer or promotion-gate change."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:52:07.652Z"}],"before_hash":"c3604f90e82634b162615bbd002aa4d4583d9022d09d08eb92b75b05013e4a54","after_hash":"3494c5bd7aa7104eae0cdcf1bd94e6c4d204f3f5231fe6e6bb8a2f878b9e07ef","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"afca87999461560e0aa78fb0f68aa0484d4b4fb6e07ef841803a7e7c1e38fb99"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:00:25.629Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/4","value":{"command":"node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T11:00:25.569Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:00:25.629Z"}],"before_hash":"3494c5bd7aa7104eae0cdcf1bd94e6c4d204f3f5231fe6e6bb8a2f878b9e07ef","after_hash":"ca38cd2d159c291edefd710b24699f59e090a8d7cbad5a8cbd60982c8631dfc3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"e84ea83d746655e8165c6b44a22f2792b69458e9bfe2fd0aa1e2ab891ec320df"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:00:26.993Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/3/path","value":"README.md"},{"op":"replace","path":"/metadata/docs/2/path","value":"docs/process-trainer.md"},{"op":"replace","path":"/metadata/docs/1/path","value":"docs/meta-recursive.md"},{"op":"add","path":"/metadata/docs/4","value":{"path":"RECURSIVE_TRAINING.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:00:26.993Z"}],"before_hash":"ca38cd2d159c291edefd710b24699f59e090a8d7cbad5a8cbd60982c8631dfc3","after_hash":"cf7e9c84715ef619cd27c9a86947ada27707d0d77f4acd7fbc499e9638767a52","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"82f18b49430c53e2228e69bc2be7b5d85e8cd1e65628d5a6ab5f834fe8889b40"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:00:28.454Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/28","value":{"created_at":"2026-10-18T11:00:28.454Z","author":"codex-agent","text":"The Node 26 CI failure exposed a native-memory fixture race: the daemon processes kernel OOM and init exit independently. The test now keeps an idle supervisor alive while its memory-exhausting child is genuinely OOM-killed, observes Docker OOMKilled=true within the existing bounded barrier, then releases the failed supervisor. The child prefers itself via its own positive OOM score adjustment; no simulated kill is used. The physical cap remains 192 MiB, V8 ceiling remains 1 GiB, wall allowance remains 15 seconds, and all refusal, receipt, no-successor, cleanup and resume assertions remain. Focused real-container verification passed 1/1. Restoring only the old memory fixture with the new test retained fails 0/1 at the missing kernel-event handshake; the fixed fixture is restored. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. Production trainer and promotion code are unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:00:28.454Z"}],"before_hash":"cf7e9c84715ef619cd27c9a86947ada27707d0d77f4acd7fbc499e9638767a52","after_hash":"a17ff8ed083682a6ce997f6d012e75d12e68db243288e3ae386f941f44d49528","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"4b4a8f7e6dd78153a7362cdafee79895840bf6bd6b186eaefbf95379d9661480"} diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 023b80a7..9f2e77ca 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -194,8 +194,11 @@ scoring behavior; the live receipt retains its exact measured source head. The real Compose resource faults are explicit: the deadline worker publishes real LM progress then pauses past its unchanged 15-second limit; the memory -worker has a V8 ceiling above its unchanged 192 MiB physical cgroup cap and is -actually OOM-killed. Existing no-successor, receipt, cleanup and resume assertions +worker has a V8 ceiling above its unchanged 192 MiB physical cgroup cap. Its +allocating child is actually OOM-killed; an idle supervisor stays alive until +Docker records that native OOM, then exits as failed. This bounded barrier avoids +a race between independent daemon OOM and exit notifications. A fixture-only +revert loses the required handshake and fails the retained resource test. Existing no-successor, receipt, cleanup and resume assertions remain. Guard-only reverts for recipe lineage, public visibility, programme ids, retained reservation case folding and both resource fault injectors fail; restored implementations pass. PM-linked data/recipe, crash/promotion/budget, identity and diff --git a/test/fixtures/lm-compose-memory.ts b/test/fixtures/lm-compose-memory.ts index a37c196a..1bd30735 100644 --- a/test/fixtures/lm-compose-memory.ts +++ b/test/fixtures/lm-compose-memory.ts @@ -1,14 +1,33 @@ -/** Exhaust the container's physical memory guard without loading the LM or hitting a smaller V8 heap ceiling first. */ +/** Exercise the physical memory guard while keeping PID 1 alive until Docker's real OOM evidence is observed. */ import { Buffer } from "node:buffer"; -import { appendFileSync, closeSync, fsyncSync, openSync, writeFileSync } from "node:fs"; +import { spawn } from "node:child_process"; +import { appendFileSync, closeSync, existsSync, fsyncSync, openSync, readFileSync, writeFileSync } from "node:fs"; +import { setTimeout } from "node:timers/promises"; import { getHeapStatistics } from "node:v8"; -appendFileSync("launches.ndjson", `${JSON.stringify({ started: true })}\n`); -process.stdin.resume(); -const handle = openSync("partial.json", "wx"); -try { - writeFileSync(handle, JSON.stringify({ allocation_started: true, heap_limit_bytes: getHeapStatistics().heap_size_limit })); - fsyncSync(handle); -} finally { closeSync(handle); } -const blocks: Buffer[] = []; -for (;;) blocks.push(Buffer.alloc(8 * 1024 * 1024, 1)); +/** Publish bounded fixture evidence before a process can be killed by its container's memory guard. */ +function marker(name: string, value: Record): void { + const handle = openSync(name, "wx"); + try { writeFileSync(handle, JSON.stringify(value)); fsyncSync(handle); } + finally { closeSync(handle); } +} + +if (process.argv[2] === "allocate") { + // Prefer the allocating child over the idle supervisor as the kernel's victim; the memory ceiling is unchanged. + writeFileSync("/proc/self/oom_score_adj", "1000"); + marker("partial.json", { allocation_started: true, heap_limit_bytes: getHeapStatistics().heap_size_limit, + oom_score_adjustment: Number(readFileSync("/proc/self/oom_score_adj", "utf8")) }); + const blocks: Buffer[] = []; + for (;;) blocks.push(Buffer.alloc(8 * 1024 * 1024, 1)); +} else { + appendFileSync("launches.ndjson", `${JSON.stringify({ started: true })}\n`); + process.stdin.resume(); + const child = spawn(process.execPath, ["--max-old-space-size=1024", import.meta.filename, "allocate"], { stdio: "ignore" }); + const ended = await new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => { + child.once("error", reject); child.once("exit", (code, signal) => resolve({ code, signal })); + }); + marker("memory-child.json", { exit_code: ended.code, signal: ended.signal }); + // The test releases this failed supervisor only after Docker has recorded the genuine kernel OOM notification. + while (!existsSync("memory-release.json")) await setTimeout(10); + process.exit(1); +} diff --git a/test/lm-compose.test.ts b/test/lm-compose.test.ts index 2b37d344..f7d87a33 100644 --- a/test/lm-compose.test.ts +++ b/test/lm-compose.test.ts @@ -112,6 +112,19 @@ async function until(predicate: () => boolean): Promise { for (let count = 0; count < 1200; count += 1) { if (predicate()) return; await setTimeout(25); } assert.fail("LM container barrier was not reached"); } +/** Observe the daemon's actual kernel-OOM flag before allowing the idle fixture supervisor to exit. */ +async function nativeOomRecorded(id: string, directory: string): Promise { + const deadline = performance.now() + 30_000; + for (;;) { + const remaining = deadline - performance.now(); + assert.ok(remaining > 0, "Docker did not record the native OOM within the existing barrier bound"); + const result = spawnSync("docker", ["container", "inspect", `${composeProject(id, directory)}-trainer`, "--format", "{{.State.OOMKilled}}"], + { encoding: "utf8", timeout: Math.max(1, Math.floor(Math.min(1000, remaining))) }); + assert.equal(result.status, 0, "memory fixture supervisor must remain inspectable until native OOM acknowledgement"); + if (result.stdout.trim() === "true") return; + await setTimeout(25); + } +} /** Spawn the real controller with the existing transaction-boundary barriers. */ function controller(pmRoot: string, approval: string, cfg: JsonValue, mode: string) { const child = fork(new URL("./fixtures/process-controller.ts", import.meta.url), [pmRoot, approval, JSON.stringify(cfg), mode], { silent: true, execArgv: [], env: { ...process.env, NODE_V8_COVERAGE: undefined } }); @@ -188,7 +201,21 @@ test("real Compose LM corrupt checkpoints and exceeded memory/time refuse promot const { client, coordinates, approval, pmRoot } = await processWorkspace(budget); const selected = mode === "time" ? { ...adapter("time"), allowance: { ...allowance, training_steps: 1000, wall_ms: 15_000, tokens: 1_000_000 } } : mode === "memory" ? { ...adapter(mode), memory_bytes: 201_326_592 } : adapter(mode); const cfg = mode === "time" ? { ...rawConfig(selected) as Record, fit_steps: 1000, limits: { ...example["limits"] as Record, max_steps: 2060 } } : rawConfig(selected); - await assert.rejects(runRlLoop(client, coordinates, { id: "process-drill", approval, config: cfg }), Error, `${mode}: the injected resource fault must refuse`); + const refused = assert.rejects(runRlLoop(client, coordinates, { id: "process-drill", approval, config: cfg }), Error, `${mode}: the injected resource fault must refuse`); + try { + if (mode === "memory") { + const id = processJobId(inputFor(selected), undefined, selected); const directory = processStaging(pmRoot, id); + await until(() => existsSync(join(directory, "memory-child.json"))); + const child = JSON.parse(readFileSync(join(directory, "memory-child.json"), "utf8")) as { exit_code: number | null; signal: string | null }; + assert.deepEqual(child, { exit_code: null, signal: "SIGKILL" }, "the kernel must kill the memory-exhausting child"); + await nativeOomRecorded(id, directory); + } + } finally { + if (mode === "memory") { + for (const job of await listProcessJobs(client)) writeFileSync(join(processStaging(pmRoot, job.id), "memory-release.json"), "{}"); + } + await refused; + } const [job] = await listProcessJobs(client); assert.equal(job.state, "failed"); assert.equal(job.settled, true); assert.equal(job.completion, null); assert.equal((await client.listAllComplete({})).items.filter((item) => item.type === "Run").length, 1, `${mode}: a failed fit cannot collect a successor`); assert.equal((await client.listAllComplete({})).items.filter((item) => item.type === "Generation" && item.status === "closed").length, 0); @@ -196,10 +223,11 @@ test("real Compose LM corrupt checkpoints and exceeded memory/time refuse promot const directory = processStaging(pmRoot, job.id); assert.ok(existsSync(join(directory, "input.json"))); if (mode === "memory") { assert.ok(existsSync(join(directory, "partial.json"))); - const partial = JSON.parse(readFileSync(join(directory, "partial.json"), "utf8")) as { heap_limit_bytes: number }; + const partial = JSON.parse(readFileSync(join(directory, "partial.json"), "utf8")) as { heap_limit_bytes: number; oom_score_adjustment: number }; assert.ok(partial.heap_limit_bytes > selected.memory_bytes, "the physical cgroup guard must precede the V8 heap ceiling"); + assert.equal(partial.oom_score_adjustment, 1000); const stopped = JSON.parse(readFileSync(join(directory, "compose-stop.json"), "utf8")) as { resources: { oom_killed: boolean } }; - assert.equal(stopped.resources.oom_killed, true); + assert.equal(stopped.resources.oom_killed, true, JSON.stringify(stopped.resources)); } if (mode === "time") { assert.ok(existsSync(join(directory, "events.ndjson"))); From 39e6c5eb6a67c8035f1f5d46d8e5c7394c7840ce Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 13:20:16 +0200 Subject: [PATCH 13/24] docs: record review proofs and complete release verification --- .agents/pm/features/pm-rl-meta.toon | 7 +++---- .agents/pm/features/pm-rl-whrd.toon | 7 +++---- .agents/pm/history/pm-rl-meta.jsonl | 2 ++ .agents/pm/history/pm-rl-whrd.jsonl | 2 ++ RECURSIVE_TRAINING.md | 7 +++++-- docs/meta-recursive.md | 27 ++++++++++++++++++++++----- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index aefb6444..96ed673e 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T11:01:12.428Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T11:19:52.622Z" author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[35]{created_at,author,text}: +comments[36]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -48,6 +46,7 @@ comments[35]{created_at,author,text}: "2026-10-18T10:33:04.727Z",codex-agent,"The expanded linked review run passes 7/7, zero failures/cancellations/skips, after shortening only the budget-test programme labels. Every training-sample, proposal-call, promotion, approval-replacement, malformed-charge and pretty-body assertion remains intact. This restores execution of the previously aborted budget branches without changing production code or weakening any check. Four review revert proofs remain valid against unchanged fixed functions and README. Pushing the test-only compatibility correction for a complete rerun of both isolated release gates." "2026-10-18T10:52:06.830Z",codex-agent,"Corrected-head CI run 39119714690 now passes npm Node 22 and Bun Node 26 at 617/617 with all four coverage metrics 100%; the complete budget regression and every meta branch pass. npm Node 26 also has full meta coverage but hits an existing native-memory fault fixture intermittently: its failed trainer receipt has OOMKilled false at the strict physical-OOM assertion. No meta assertion fails. Investigating and synchronizing the fault evidence rather than retrying until green or weakening the memory assertion." "2026-10-18T11:01:12.427Z",codex-agent,"The native-memory fixture correction passes both direct and restored PM-linked real-container verification 1/1, zero failures/skips. A fixture-only behavioral revert fails 0/1 at the missing durable child-death handshake; restoring it passes. The test observes an actual kernel SIGKILL and Docker OOMKilled=true before releasing an idle failed supervisor, retaining original memory/time caps and every existing refusal assertion. Build:test, lint, duplicates and documentation checks pass: 35 source files, 295 documented declarations. Two release variants already pass 617/617 on 2820234; the complete three-variant isolated release matrix will rerun on this fixture correction. Registry currently reports CLI 2026.10.18; pinned SDK remains 2026.10.13 as required. No live retraining or statistical changes were needed." + "2026-10-18T11:19:51.055Z",codex-agent,"Source-verification CI run 39121554923 on 798cfe8af45371ddec478e5b8c2e79259be0fce5 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 617/617, zero failures/cancellations/skips, all four coverage metrics 100%, 35 required source files and 295 documented declarations; identity, publish attestation, production audit, packaging and changelog checks pass. CodeQL passes. The strict native OOM and deadline test passes in every variant. Four independent review-finding reverts plus the OOM handshake revert fail 0/1 each; restored linked checks pass 7/7 and 1/1. Thirteen behavioral revert proofs now cover the complete feature and review work. A fresh no-local clone passes strict health with merge drivers and isolated identity, retaining pre-existing advisory warnings and append-only history. All three review findings were replied to after push; CodeRabbit resolved them by static inspection without executing tests. Zero open GitHub issues; Greptile trial-ended notices provide no review approval. Real-data and sanity receipts are unchanged. The final documentation/claim-release commit will receive another exact-head matrix run; no merge or release is authorized." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/features/pm-rl-whrd.toon b/.agents/pm/features/pm-rl-whrd.toon index 38790405..e3baedc4 100644 --- a/.agents/pm/features/pm-rl-whrd.toon +++ b/.agents/pm/features/pm-rl-whrd.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags[3]: execution,llm-adapter,recursive-training created_at: "2026-10-15T22:07:13.392Z" -updated_at: "2026-10-18T11:00:28.454Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T11:19:53.365Z" author: codex-agent acceptance_criteria: "Two real generations with successor collection; SIGKILL recovery, cancellation, corrupt checkpoint and limit refusals, one-launch contention; behavioural revert proofs and unchanged npm and Bun release gates." parent: pm-rl-apvf -comments[29]{created_at,author,text}: +comments[30]{created_at,author,text}: "2026-10-15T22:07:43.111Z",codex-agent,"Design: extend the existing process contract with a typed LM payload and checkpoint validator; share owner fences, atomic reservation, staged adoption, cancellation and settlement. Keep held-out examples in the controller. Bind immutable image, memory and CPU ceilings into programme and job identity; send only frozen weights, source adapter, training strings and collected rewards to a networkless non-root container. Add real recursive generations and crash/cancellation/limit/contention drills, then behavioural revert proofs and unchanged release gates." "2026-10-15T22:16:06.750Z",codex-agent,"First real Compose evidence: generation 1 checkpoint 058aa3d2c08438abd18cf0e9b455aca99ddb95492de852201c55c79a0672130d -> 37e503748a170be32e1d506997b6c0cc5c9ee256b24ab01fb49cf0564da07b4c; held-out sampled reward 0.183854, six steps, 1152 target tokens, observed wall 5567 ms, fit CPU 820 ms, peak RSS 138629120 bytes, retained staging 88930 bytes. Generation 2 collected with that promoted digest and trained -> 086f78992283cba37929321abe3961ca6132a52c332bf8a8387a52f22141cbdb; reward 0.292396, six steps, 1152 tokens, wall 5654 ms, CPU 803 ms, peak RSS 143323136 bytes, staging 92364 bytes. Both promoted through the existing gate. Real controller SIGKILL after completion before receipt commit recovered the same checkpoint and original reservation with one launch. Mid-fit cancellation retained input/events and process_cancelled. Full drills and coverage verification continue. The first linked run reached its default 120-second timeout; rerun will explicitly allow the complete integration duration." "2026-10-15T22:24:09.789Z",codex-agent,"Validated linked run: pm test pm-rl-whrd --run --progress --timeout 900 passed 8/8, zero failures/skips/cancellations/todo. Real kernel memory drill retained partial allocation evidence and daemon oom_killed=true at 201326592 bytes; the time drill began the real 1000-step fit before exceeding its 15000 ms allowance. Both refused promotion and successor collection. Two-generation execution took 54134.161 ms; independent verification/replay/status took 4470.981 ms. Canonical hashes and held-out objectives match the first measurement. Final fit resources: generation 1 wall 4297 ms, CPU 713 ms, RSS 138207232 bytes, staging 89057 bytes; generation 2 wall 4266 ms, CPU 759 ms, RSS 144183296 bytes, staging 92509 bytes; both six steps and 1152 target tokens. Daemon receipts verify memory=268435456, CPU=1, no network and non-root user. Existing Compose barrier variability is tracked in pm-rl-8nev. Revert proofs and complete release gates remain in progress." @@ -42,6 +40,7 @@ comments[29]{created_at,author,text}: "2026-10-18T07:03:16.944Z",codex-agent,"Final current validation: CI run https://github.com/unbraind/pm-rl/actions/runs/39104826277 on 445b232 passes all three complete gates (npm Node 22, npm Node 26, Bun Node 26), 612/612 each, zero skips, all four coverage metrics 100% across 35 required sources and 295 documented declarations. The real corruption/native-OOM/15-second-deadline refusal drill passes with every original failure, no-successor, cleanup and resume assertion retained. Its two fault-guard reverts fail 0/1 each; restored physical and linked verification passes 1/1. The original merged-PR acceptance audit remains Met, now supplemented by stable current fault injection. No production trainer or promotion changes, pin bump, larger physical allowance or release enablement. Leave in progress for orchestrator closure; release the claim after these receipts." "2026-10-18T10:52:07.652Z",codex-agent,"Review-round full CI exposed a physical-memory fault race: one Node 26 runner recorded OOMKilled false, while Node 22 and Bun runners passed the same strict native-OOM case. The current minimal allocator exits as soon as the kernel kills its PID 1. Docker records OOM notifications separately from task exit; terminal cleanup can observe incomplete daemon OOM evidence. The fixture will keep a minimal parent alive after a native memory-exhausting child is killed and release that parent only after the test observes Docker's real OOM flag. Preserve the 192 MiB cap, 1 GiB V8 ceiling, original deadlines, refusal/no-successor/settlement/cleanup/resume assertions; no production trainer or promotion-gate change." "2026-10-18T11:00:28.454Z",codex-agent,"The Node 26 CI failure exposed a native-memory fixture race: the daemon processes kernel OOM and init exit independently. The test now keeps an idle supervisor alive while its memory-exhausting child is genuinely OOM-killed, observes Docker OOMKilled=true within the existing bounded barrier, then releases the failed supervisor. The child prefers itself via its own positive OOM score adjustment; no simulated kill is used. The physical cap remains 192 MiB, V8 ceiling remains 1 GiB, wall allowance remains 15 seconds, and all refusal, receipt, no-successor, cleanup and resume assertions remain. Focused real-container verification passed 1/1. Restoring only the old memory fixture with the new test retained fails 0/1 at the missing kernel-event handshake; the fixed fixture is restored. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. Production trainer and promotion code are unchanged." + "2026-10-18T11:19:51.882Z",codex-agent,"Native resource-drill synchronization is verified in source CI run 39121554923 on 798cfe8: npm Node 22/26 and Bun Node 26 each pass 617/617 and all four coverage metrics at 100%; all three run the real strict OOM/deadline refusal case successfully. The allocating child is kernel-killed and Docker native OOM is observed before the supervisor exits, with unchanged memory/time bounds and all original assertions. The fixture-only revert fails and restored direct plus PM-linked real-container runs pass 1/1. Acceptance remains Met; this item stays in progress for orchestrator verification. Releasing the implementation claim at handoff; no close, merge or release publication is performed." files[21]{path,scope}: .dockerignore,project compose.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 34a2f679..56bc4798 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -64,3 +64,5 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T10:33:04.727Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/32","value":{"created_at":"2026-10-18T10:33:04.727Z","author":"codex-agent","text":"The expanded linked review run passes 7/7, zero failures/cancellations/skips, after shortening only the budget-test programme labels. Every training-sample, proposal-call, promotion, approval-replacement, malformed-charge and pretty-body assertion remains intact. This restores execution of the previously aborted budget branches without changing production code or weakening any check. Four review revert proofs remain valid against unchanged fixed functions and README. Pushing the test-only compatibility correction for a complete rerun of both isolated release gates."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:33:04.727Z"}],"before_hash":"d785992dd3d39a795db29504d45cc9f6b4827cce2eedbd01f3e0b26150c56b1b","after_hash":"7a016d82c4798d49a54b3814d0c7f73543a9bf3633e59d4a440b8c193360fc94","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"97feab5a80cc54c098b78fd1fdc023a606695c5ceab5d22ed28535be94ccdab9"} {"hash_algorithm":"sha256","ts":"2026-10-18T10:52:06.830Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/33","value":{"created_at":"2026-10-18T10:52:06.830Z","author":"codex-agent","text":"Corrected-head CI run 39119714690 now passes npm Node 22 and Bun Node 26 at 617/617 with all four coverage metrics 100%; the complete budget regression and every meta branch pass. npm Node 26 also has full meta coverage but hits an existing native-memory fault fixture intermittently: its failed trainer receipt has OOMKilled false at the strict physical-OOM assertion. No meta assertion fails. Investigating and synchronizing the fault evidence rather than retrying until green or weakening the memory assertion."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T10:52:06.830Z"}],"before_hash":"7a016d82c4798d49a54b3814d0c7f73543a9bf3633e59d4a440b8c193360fc94","after_hash":"4860b7293a11e98761883450d4e5d2d4cc1416416ead4d4569fdcdfa6ac0d9ec","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"13064a9b0dbeef1346c4f3cbc9411655eca9ab3eaf65a0e9911da39811221f6c"} {"hash_algorithm":"sha256","ts":"2026-10-18T11:01:12.428Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/34","value":{"created_at":"2026-10-18T11:01:12.427Z","author":"codex-agent","text":"The native-memory fixture correction passes both direct and restored PM-linked real-container verification 1/1, zero failures/skips. A fixture-only behavioral revert fails 0/1 at the missing durable child-death handshake; restoring it passes. The test observes an actual kernel SIGKILL and Docker OOMKilled=true before releasing an idle failed supervisor, retaining original memory/time caps and every existing refusal assertion. Build:test, lint, duplicates and documentation checks pass: 35 source files, 295 documented declarations. Two release variants already pass 617/617 on 2820234; the complete three-variant isolated release matrix will rerun on this fixture correction. Registry currently reports CLI 2026.10.18; pinned SDK remains 2026.10.13 as required. No live retraining or statistical changes were needed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:01:12.428Z"}],"before_hash":"4860b7293a11e98761883450d4e5d2d4cc1416416ead4d4569fdcdfa6ac0d9ec","after_hash":"bf643730b549790bb66967fee821751b4c3302accc420aaeb924b630013a8cda","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"3118e07fdaf40e6bf9aa3ac7f5a76d54e771cb701fd1b024fe279d09110bd63d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:19:51.055Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/35","value":{"created_at":"2026-10-18T11:19:51.055Z","author":"codex-agent","text":"Source-verification CI run 39121554923 on 798cfe8af45371ddec478e5b8c2e79259be0fce5 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 617/617, zero failures/cancellations/skips, all four coverage metrics 100%, 35 required source files and 295 documented declarations; identity, publish attestation, production audit, packaging and changelog checks pass. CodeQL passes. The strict native OOM and deadline test passes in every variant. Four independent review-finding reverts plus the OOM handshake revert fail 0/1 each; restored linked checks pass 7/7 and 1/1. Thirteen behavioral revert proofs now cover the complete feature and review work. A fresh no-local clone passes strict health with merge drivers and isolated identity, retaining pre-existing advisory warnings and append-only history. All three review findings were replied to after push; CodeRabbit resolved them by static inspection without executing tests. Zero open GitHub issues; Greptile trial-ended notices provide no review approval. Real-data and sanity receipts are unchanged. The final documentation/claim-release commit will receive another exact-head matrix run; no merge or release is authorized."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:19:51.055Z"}],"before_hash":"bf643730b549790bb66967fee821751b4c3302accc420aaeb924b630013a8cda","after_hash":"c49d36ed2e8c8c94410cd5ff56465363bd2298b63e1351045ef7949066f18ddd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2fd950b07963cd7b02b96fadb99eacbbccc4b7def5144b44dc63e4c936f75ab2"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:19:52.622Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:19:52.622Z"}],"before_hash":"c49d36ed2e8c8c94410cd5ff56465363bd2298b63e1351045ef7949066f18ddd","after_hash":"be8ae988f5206818f68e2dc4173d3b30962b178daacf8362d846aa2a30063922","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"4debf400e866d98eeedd356eea45246fce5e7e577caa331572cac37da7087cdb"} diff --git a/.agents/pm/history/pm-rl-whrd.jsonl b/.agents/pm/history/pm-rl-whrd.jsonl index 9cc372e0..b9e335e6 100644 --- a/.agents/pm/history/pm-rl-whrd.jsonl +++ b/.agents/pm/history/pm-rl-whrd.jsonl @@ -53,3 +53,5 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T11:00:25.629Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/4","value":{"command":"node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T11:00:25.569Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:00:25.629Z"}],"before_hash":"3494c5bd7aa7104eae0cdcf1bd94e6c4d204f3f5231fe6e6bb8a2f878b9e07ef","after_hash":"ca38cd2d159c291edefd710b24699f59e090a8d7cbad5a8cbd60982c8631dfc3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"e84ea83d746655e8165c6b44a22f2792b69458e9bfe2fd0aa1e2ab891ec320df"} {"hash_algorithm":"sha256","ts":"2026-10-18T11:00:26.993Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/3/path","value":"README.md"},{"op":"replace","path":"/metadata/docs/2/path","value":"docs/process-trainer.md"},{"op":"replace","path":"/metadata/docs/1/path","value":"docs/meta-recursive.md"},{"op":"add","path":"/metadata/docs/4","value":{"path":"RECURSIVE_TRAINING.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:00:26.993Z"}],"before_hash":"ca38cd2d159c291edefd710b24699f59e090a8d7cbad5a8cbd60982c8631dfc3","after_hash":"cf7e9c84715ef619cd27c9a86947ada27707d0d77f4acd7fbc499e9638767a52","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"82f18b49430c53e2228e69bc2be7b5d85e8cd1e65628d5a6ab5f834fe8889b40"} {"hash_algorithm":"sha256","ts":"2026-10-18T11:00:28.454Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/28","value":{"created_at":"2026-10-18T11:00:28.454Z","author":"codex-agent","text":"The Node 26 CI failure exposed a native-memory fixture race: the daemon processes kernel OOM and init exit independently. The test now keeps an idle supervisor alive while its memory-exhausting child is genuinely OOM-killed, observes Docker OOMKilled=true within the existing bounded barrier, then releases the failed supervisor. The child prefers itself via its own positive OOM score adjustment; no simulated kill is used. The physical cap remains 192 MiB, V8 ceiling remains 1 GiB, wall allowance remains 15 seconds, and all refusal, receipt, no-successor, cleanup and resume assertions remain. Focused real-container verification passed 1/1. Restoring only the old memory fixture with the new test retained fails 0/1 at the missing kernel-event handshake; the fixed fixture is restored. Exact command: node --test --test-name-pattern=\"real Compose LM corrupt checkpoints\" test/lm-compose.test.ts. Production trainer and promotion code are unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:00:28.454Z"}],"before_hash":"cf7e9c84715ef619cd27c9a86947ada27707d0d77f4acd7fbc499e9638767a52","after_hash":"a17ff8ed083682a6ce997f6d012e75d12e68db243288e3ae386f941f44d49528","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"4b4a8f7e6dd78153a7362cdafee79895840bf6bd6b186eaefbf95379d9661480"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:19:51.882Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/29","value":{"created_at":"2026-10-18T11:19:51.882Z","author":"codex-agent","text":"Native resource-drill synchronization is verified in source CI run 39121554923 on 798cfe8: npm Node 22/26 and Bun Node 26 each pass 617/617 and all four coverage metrics at 100%; all three run the real strict OOM/deadline refusal case successfully. The allocating child is kernel-killed and Docker native OOM is observed before the supervisor exits, with unchanged memory/time bounds and all original assertions. The fixture-only revert fails and restored direct plus PM-linked real-container runs pass 1/1. Acceptance remains Met; this item stays in progress for orchestrator verification. Releasing the implementation claim at handoff; no close, merge or release publication is performed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:19:51.882Z"}],"before_hash":"a17ff8ed083682a6ce997f6d012e75d12e68db243288e3ae386f941f44d49528","after_hash":"f42d96fd477110cc48f8f8aaa9e7dcbea49cefd0cc76c9c52a7d614b83f153e4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"590a6ccd1c0cd3d9e013bbf6e4cb1954b1a2ee99dd19865e0ad52d9100de9153"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:19:53.365Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:19:53.365Z"}],"before_hash":"f42d96fd477110cc48f8f8aaa9e7dcbea49cefd0cc76c9c52a7d614b83f153e4","after_hash":"0dd17d996576609a02bf9e559405395f33131cf6d2bcc3a938651b8b333f0c61","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fd74b153d7ed0da3cf0a06a04054c57f90d21b3b8526ec5bc6c1226f58bd5644"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 683aaff3..21c5bd25 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -88,10 +88,13 @@ Adapters report structured progress and completion evidence over a documented st result, not real-tracker improvement. No gate or real feature was weakened. [Complete release verification](https://github.com/unbraind/pm-rl/pull/84/checks) passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: - 613/613 each, zero failures/skips, all four coverage metrics 100% across all + 617/617 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared - budget, conditional promotion and resource-refusal regressions pass; eight + budget, conditional promotion and resource-refusal regressions pass; thirteen behaviour-only reverts fail with tests retained and restored code passes. + The review round fixes canonical receipt identity, bounded programme ids and + README command syntax; the physical OOM test waits for real daemon evidence + before its failed supervisor exits. Limits and promotion thresholds are unchanged. ## Data boundary and capacity diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 9f2e77ca..42f11357 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -182,10 +182,11 @@ predictions, and full disagreement. ## Release verification -The [preceding CI run](https://github.com/unbraind/pm-rl/actions/runs/39110114926) +The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39121554923) +on `798cfe8af45371ddec478e5b8c2e79259be0fce5` executes `npm run release:check` on Node 22 and 26 and `bun run release:check` on Node 26 with isolated HOME and global/system Git configuration. Each passes -613/613 tests, zero failures/skips, 100% statements/lines/branches/functions over +617/617 tests, zero failures/skips, 100% statements/lines/branches/functions over all 35 declared sources, 295 documented declarations, and zero duplicate clones or production audit findings. Thresholds, dependency pins and release approval are unchanged. The live evidence names the measured production source commit; @@ -202,7 +203,9 @@ revert loses the required handshake and fails the retained resource test. Existi remain. Guard-only reverts for recipe lineage, public visibility, programme ids, retained reservation case folding and both resource fault injectors fail; restored implementations pass. PM-linked data/recipe, crash/promotion/budget, identity and -resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. +resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. The expanded +review command passes 7/7. Thirteen independent behavioral reverts fail across +the feature and both review rounds; restoring the implementations passes. A separate local full-suite attempt hit the unchanged 300-second HTTP crash-drill deadline under host load and was retained as failed evidence. The required complete @@ -214,5 +217,19 @@ programme ids at 20 characters, and executes the corrected README command in a regression test. Four independent behavior-only reverts fail with those tests retained; restoring the fixes passes. Unreadable receipt evidence propagates, and legacy proposal attempts without an identity refuse. Proposal bindings and -statistical gates are unchanged. Thread resolution is left to reviewers. The PR remains unmerged, work items stay open for the orchestrator, -and no final-head review approval is claimed. +statistical gates are unchanged. CodeRabbit subsequently inspected the fixes at +`54b2573` and resolved its three threads itself; it did not execute the repository tests. No author resolution +request was made. There are no open GitHub issue findings. Greptile reports an +expired trial; skipped or neutral reviewer checks provide no approval. The PR +remains unmerged, work items stay open for the orchestrator, and no final-head +review approval is claimed. + +The first review-round matrix correctly failed 616/617 because two existing +budget-test programme labels exceeded the new id bound; only those labels were +shortened, preserving every assertion. The next run passed Node 22 npm and +Node 26 Bun at 617/617 but exposed the independent Docker OOM/exit notification +race in Node 26 npm. The supervised native allocator above removes that race; +the source-verification run passes all three complete gates with every original +resource assertion retained. Fresh-clone strict tracker health passes with merge +drivers and isolated Git configuration. Existing telemetry and provenance +advisories remain, and all tracker histories preserve their main-branch prefix. From 268d04a9fdd22960a78d9d675a6c342f29153c74 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:17:51 +0200 Subject: [PATCH 14/24] fix: recover meta leases and reserve inner promotion capacity --- .agents/pm/features/pm-rl-meta.toon | 12 ++- .agents/pm/history/pm-rl-meta.jsonl | 5 ++ RECURSIVE_TRAINING.md | 5 +- docs/meta-recursive.md | 37 +++++++- examples/meta-approval.md | 3 + index.ts | 36 ++++---- meta.ts | 37 ++++++-- test/meta.test.ts | 134 ++++++++++++++++++++++++++-- tracker-environment.ts | 1 + 9 files changed, 235 insertions(+), 35 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 96ed673e..f88d6b2d 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,11 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T11:19:52.622Z" +updated_at: "2026-10-18T12:17:47.381Z" +assignee: codex-agent +claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[36]{created_at,author,text}: +comments[39]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -47,6 +49,9 @@ comments[36]{created_at,author,text}: "2026-10-18T10:52:06.830Z",codex-agent,"Corrected-head CI run 39119714690 now passes npm Node 22 and Bun Node 26 at 617/617 with all four coverage metrics 100%; the complete budget regression and every meta branch pass. npm Node 26 also has full meta coverage but hits an existing native-memory fault fixture intermittently: its failed trainer receipt has OOMKilled false at the strict physical-OOM assertion. No meta assertion fails. Investigating and synchronizing the fault evidence rather than retrying until green or weakening the memory assertion." "2026-10-18T11:01:12.427Z",codex-agent,"The native-memory fixture correction passes both direct and restored PM-linked real-container verification 1/1, zero failures/skips. A fixture-only behavioral revert fails 0/1 at the missing durable child-death handshake; restoring it passes. The test observes an actual kernel SIGKILL and Docker OOMKilled=true before releasing an idle failed supervisor, retaining original memory/time caps and every existing refusal assertion. Build:test, lint, duplicates and documentation checks pass: 35 source files, 295 documented declarations. Two release variants already pass 617/617 on 2820234; the complete three-variant isolated release matrix will rerun on this fixture correction. Registry currently reports CLI 2026.10.18; pinned SDK remains 2026.10.13 as required. No live retraining or statistical changes were needed." "2026-10-18T11:19:51.055Z",codex-agent,"Source-verification CI run 39121554923 on 798cfe8af45371ddec478e5b8c2e79259be0fce5 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 617/617, zero failures/cancellations/skips, all four coverage metrics 100%, 35 required source files and 295 documented declarations; identity, publish attestation, production audit, packaging and changelog checks pass. CodeQL passes. The strict native OOM and deadline test passes in every variant. Four independent review-finding reverts plus the OOM handshake revert fail 0/1 each; restored linked checks pass 7/7 and 1/1. Thirteen behavioral revert proofs now cover the complete feature and review work. A fresh no-local clone passes strict health with merge drivers and isolated identity, retaining pre-existing advisory warnings and append-only history. All three review findings were replied to after push; CodeRabbit resolved them by static inspection without executing tests. Zero open GitHub issues; Greptile trial-ended notices provide no review approval. Real-data and sanity receipts are unchanged. The final documentation/claim-release commit will receive another exact-head matrix run; no merge or release is authorized." + "2026-10-18T11:57:45.340Z",codex-agent,"New full CodeRabbit review of 39e6c5e has two unresolved findings: unsupported recovery guidance/options for ambiguous outer meta leases, and missing shared inner-promotion headroom plus swallowed promotion-budget refusal. Read both threads and the complete newest review body; zero open GitHub issue findings. The branch is clean, ahead of main and not behind. Reusing this feature item for supported operator recovery and fail-closed promotion accounting with real tracker regressions and behavioral revert proofs. Prior acceptance receipts and statistical thresholds remain unchanged." + "2026-10-18T12:15:15.766Z",codex-agent,"Both new review findings are implemented. MetaRequest and the public command forward force takeover and the actual approval; refusals name the supported meta run command with file, dataset, approval and proposer options. A digest-only holder audit goes to the existing approval before replacing the lease, including before the first programme receipt. Verified live and unverifiable holders still refuse. Shared promotion headroom is (1 + meta_generations * candidates) times the maximum declared recipe steps, stored separately from meta_budget and checked atomically against permitted_promotions. Canonical reserved namespaces consume held headroom once; outside promotions count separately. Core accounting exposes only promoted ids, never Generation bodies or held-out examples, to search. Inner promotion_refused reports specifically naming the approved promotion budget throw meta_inner_promotion_budget, including after an accepted prior generation; non-budget refusal replay remains allowed. Full meta suite passed 22/22; build, test compilation, lint, duplicates and docs gates pass with 35 sources and 295 declarations. Four isolated behavioral reverts each fail 0/1: remove only force forwarding, restore only inner-loop refusal guidance, restore only the old reserveMeta function, or remove only the budget-refusal guard. Every fixed source is restored. The complete feature now has seventeen revert proofs. Pinned SDK rejects a Generation type filter before that custom type exists; certified metadata establishes an empty inventory without changing schema or swallowing read errors. Registry CLI is 2026.10.18; the repo SDK pin remains 2026.10.13." + "2026-10-18T12:17:47.381Z",codex-agent,"Restored PM-linked review command passes 4/4, zero failures/cancellations/skips, using the repository-pinned CLI with explicit author. The outside-consumption regression includes another loop sharing the reservation prefix but outside its canonical inner namespace, so a broad prefix cannot hide consumed promotions. The full meta suite passed 22/22 and the focused linked run also covers the final pre-publication audit target. Result persistence remains disabled by project policy, so this comment records the receipt. Previous complete release CI on 39e6c5e passed 617/617 in all three variants; the new source has 621 tests and will be checked by both complete commands with isolated HOME/Git identity. No new passing full-gate result is claimed yet. Live and sanity receipts, the promotion criterion, dependency pins and releases remain unchanged." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project @@ -72,7 +77,7 @@ files[24]{path,scope}: test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[7]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[8]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop @@ -80,6 +85,7 @@ tests[7]{command,scope,timeout_seconds,provenance{author,created_at,source_kind, "node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T07:43:42.817Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T09:52:27.463Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity|one pre-approved\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T10:31:09.686Z",local_mutation,feat/meta-recursive-recipe-loop + "node --test --test-name-pattern=\"ambiguous outer meta|shared inner promotion|promotion headroom counts|inner promotion-budget\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T12:15:16.768Z",local_mutation,feat/meta-recursive-recipe-loop docs[7]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 56bc4798..a65fb4a8 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -66,3 +66,8 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T11:01:12.428Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/34","value":{"created_at":"2026-10-18T11:01:12.427Z","author":"codex-agent","text":"The native-memory fixture correction passes both direct and restored PM-linked real-container verification 1/1, zero failures/skips. A fixture-only behavioral revert fails 0/1 at the missing durable child-death handshake; restoring it passes. The test observes an actual kernel SIGKILL and Docker OOMKilled=true before releasing an idle failed supervisor, retaining original memory/time caps and every existing refusal assertion. Build:test, lint, duplicates and documentation checks pass: 35 source files, 295 documented declarations. Two release variants already pass 617/617 on 2820234; the complete three-variant isolated release matrix will rerun on this fixture correction. Registry currently reports CLI 2026.10.18; pinned SDK remains 2026.10.13 as required. No live retraining or statistical changes were needed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:01:12.428Z"}],"before_hash":"4860b7293a11e98761883450d4e5d2d4cc1416416ead4d4569fdcdfa6ac0d9ec","after_hash":"bf643730b549790bb66967fee821751b4c3302accc420aaeb924b630013a8cda","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"3118e07fdaf40e6bf9aa3ac7f5a76d54e771cb701fd1b024fe279d09110bd63d"} {"hash_algorithm":"sha256","ts":"2026-10-18T11:19:51.055Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/35","value":{"created_at":"2026-10-18T11:19:51.055Z","author":"codex-agent","text":"Source-verification CI run 39121554923 on 798cfe8af45371ddec478e5b8c2e79259be0fce5 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 617/617, zero failures/cancellations/skips, all four coverage metrics 100%, 35 required source files and 295 documented declarations; identity, publish attestation, production audit, packaging and changelog checks pass. CodeQL passes. The strict native OOM and deadline test passes in every variant. Four independent review-finding reverts plus the OOM handshake revert fail 0/1 each; restored linked checks pass 7/7 and 1/1. Thirteen behavioral revert proofs now cover the complete feature and review work. A fresh no-local clone passes strict health with merge drivers and isolated identity, retaining pre-existing advisory warnings and append-only history. All three review findings were replied to after push; CodeRabbit resolved them by static inspection without executing tests. Zero open GitHub issues; Greptile trial-ended notices provide no review approval. Real-data and sanity receipts are unchanged. The final documentation/claim-release commit will receive another exact-head matrix run; no merge or release is authorized."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:19:51.055Z"}],"before_hash":"bf643730b549790bb66967fee821751b4c3302accc420aaeb924b630013a8cda","after_hash":"c49d36ed2e8c8c94410cd5ff56465363bd2298b63e1351045ef7949066f18ddd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2fd950b07963cd7b02b96fadb99eacbbccc4b7def5144b44dc63e4c936f75ab2"} {"hash_algorithm":"sha256","ts":"2026-10-18T11:19:52.622Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:19:52.622Z"}],"before_hash":"c49d36ed2e8c8c94410cd5ff56465363bd2298b63e1351045ef7949066f18ddd","after_hash":"be8ae988f5206818f68e2dc4173d3b30962b178daacf8362d846aa2a30063922","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"4debf400e866d98eeedd356eea45246fce5e7e577caa331572cac37da7087cdb"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:57:43.961Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:57:43.961Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"be8ae988f5206818f68e2dc4173d3b30962b178daacf8362d846aa2a30063922","after_hash":"0da4ed04b6428fb9c38b1d8a436f43054b9e40f92794907548fd3a4abab1bafc","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d6c7bf6438cb0f00cd94b29cbcec0c7b98334a2d87e9ab9f4f91b648d1dfd48d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T11:57:45.341Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/36","value":{"created_at":"2026-10-18T11:57:45.340Z","author":"codex-agent","text":"New full CodeRabbit review of 39e6c5e has two unresolved findings: unsupported recovery guidance/options for ambiguous outer meta leases, and missing shared inner-promotion headroom plus swallowed promotion-budget refusal. Read both threads and the complete newest review body; zero open GitHub issue findings. The branch is clean, ahead of main and not behind. Reusing this feature item for supported operator recovery and fail-closed promotion accounting with real tracker regressions and behavioral revert proofs. Prior acceptance receipts and statistical thresholds remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T11:57:45.341Z"}],"before_hash":"0da4ed04b6428fb9c38b1d8a436f43054b9e40f92794907548fd3a4abab1bafc","after_hash":"80618012595dd11543cefa45e4712d08087a6b9da1c27f506c6a7c9e1d3dea55","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"61bf0730b4eab112b4d767a7c25f1dfc6e95dc67a66e120fbfcb6a13d4b61f5e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:15:15.766Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/37","value":{"created_at":"2026-10-18T12:15:15.766Z","author":"codex-agent","text":"Both new review findings are implemented. MetaRequest and the public command forward force takeover and the actual approval; refusals name the supported meta run command with file, dataset, approval and proposer options. A digest-only holder audit goes to the existing approval before replacing the lease, including before the first programme receipt. Verified live and unverifiable holders still refuse. Shared promotion headroom is (1 + meta_generations * candidates) times the maximum declared recipe steps, stored separately from meta_budget and checked atomically against permitted_promotions. Canonical reserved namespaces consume held headroom once; outside promotions count separately. Core accounting exposes only promoted ids, never Generation bodies or held-out examples, to search. Inner promotion_refused reports specifically naming the approved promotion budget throw meta_inner_promotion_budget, including after an accepted prior generation; non-budget refusal replay remains allowed. Full meta suite passed 22/22; build, test compilation, lint, duplicates and docs gates pass with 35 sources and 295 declarations. Four isolated behavioral reverts each fail 0/1: remove only force forwarding, restore only inner-loop refusal guidance, restore only the old reserveMeta function, or remove only the budget-refusal guard. Every fixed source is restored. The complete feature now has seventeen revert proofs. Pinned SDK rejects a Generation type filter before that custom type exists; certified metadata establishes an empty inventory without changing schema or swallowing read errors. Registry CLI is 2026.10.18; the repo SDK pin remains 2026.10.13."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:15:15.766Z"}],"before_hash":"80618012595dd11543cefa45e4712d08087a6b9da1c27f506c6a7c9e1d3dea55","after_hash":"4afab43ba88b6d1089e9d01cc5a0c523a92429e0f914c86125c3f7ffa83ed1d3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f15484a3927041d34674d7b872066826774db943094d189bfce201a0d159b322"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:15:16.820Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/7","value":{"command":"node --test --test-name-pattern=\"ambiguous outer meta|shared inner promotion|promotion headroom counts|inner promotion-budget\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T12:15:16.768Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:15:16.820Z"}],"before_hash":"4afab43ba88b6d1089e9d01cc5a0c523a92429e0f914c86125c3f7ffa83ed1d3","after_hash":"9f2789e259162dbcf07eeb073bf3cc0d52adb8b323295bc5c0b72972435ce760","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"e0dde2e128720e65611c9a00c4b79ead5057f5658f83a2d1055919c1bfdce4b7"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:17:47.381Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/38","value":{"created_at":"2026-10-18T12:17:47.381Z","author":"codex-agent","text":"Restored PM-linked review command passes 4/4, zero failures/cancellations/skips, using the repository-pinned CLI with explicit author. The outside-consumption regression includes another loop sharing the reservation prefix but outside its canonical inner namespace, so a broad prefix cannot hide consumed promotions. The full meta suite passed 22/22 and the focused linked run also covers the final pre-publication audit target. Result persistence remains disabled by project policy, so this comment records the receipt. Previous complete release CI on 39e6c5e passed 617/617 in all three variants; the new source has 621 tests and will be checked by both complete commands with isolated HOME/Git identity. No new passing full-gate result is claimed yet. Live and sanity receipts, the promotion criterion, dependency pins and releases remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:17:47.381Z"}],"before_hash":"9f2789e259162dbcf07eeb073bf3cc0d52adb8b323295bc5c0b72972435ce760","after_hash":"9cd5abe82a012ac67822e6350c81ba6e1221d4a7dfb4077015203c74d0a268c7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e902c9bd41afbbde09b3751af655021eba6cba47d2f1ce92247b72743573677b"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 21c5bd25..851907db 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -90,11 +90,14 @@ Adapters report structured progress and completion evidence over a documented st passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: 617/617 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared - budget, conditional promotion and resource-refusal regressions pass; thirteen + budget, conditional promotion and resource-refusal regressions pass; seventeen behaviour-only reverts fail with tests retained and restored code passes. The review round fixes canonical receipt identity, bounded programme ids and README command syntax; the physical OOM test waits for real daemon evidence before its failed supervisor exits. Limits and promotion thresholds are unchanged. + The next review adds supported audited outer-lease recovery and atomic inner + promotion headroom. Budget exhaustion cannot become recipe evidence; the + complete meta suite passes 22/22 and four new behavioral reverts fail. ## Data boundary and capacity diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 42f11357..e0710f47 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -59,7 +59,18 @@ One **existing** Decision must contain `permitted_promotions`, `resource_budget` and `meta_budget`. Search never creates, updates or enlarges it. Before fitting, an SDK workspace transaction reserves worst-case collection samples, proposal requests and recipe-promotion slots against all programmes using that Decision. +It separately reserves `(1 + meta_generations * candidates) * 2` inner promotion +slots against `permitted_promotions`, using the declared maximum recipe steps. +The reservation records `promotion_headroom`; already-promoted generations in +its canonical inner namespaces consume that held capacity once. Promotions +outside matching reservations consume additional capacity. Both counts are +checked inside the same SDK writer transaction, so competing outer programmes +cannot reserve the same headroom. A budget refusal from an inner promotion is +an accounting failure and never becomes recipe evidence, even if an earlier +inner generation promoted. Other intentional promotion refusals are unchanged. These conservative reservations remain held after failure or cancellation. +Legacy reservations without promotion headroom fail closed; search cannot +reclaim or silently replace them. Each inner fit also uses the existing atomic process resource reservation, measured completion receipt and settlement. Search cannot spend above either allowance. The packaged process trainer is the only selectable meta trainer. @@ -74,7 +85,9 @@ pm rl meta run tracker-search --file examples/meta-trackers.json --dataset --approval --force-takeover +``` + +The refusal names this supported command, with placeholders for the original +file and dataset. Takeover appends a digest-only holder audit to the existing +approval Decision before replacing the lease, including before the first +programme receipt exists. A verified live or unverifiable holder still blocks; +force cannot bypass process identity checks or a contended phase mutex. The 15-minute whole-run watchdog also applies to `npm run test:live`. The synthetic committed fixture and real temporary SDK trackers exercise this @@ -204,7 +229,7 @@ remain. Guard-only reverts for recipe lineage, public visibility, programme ids, retained reservation case folding and both resource fault injectors fail; restored implementations pass. PM-linked data/recipe, crash/promotion/budget, identity and resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. The expanded -review command passes 7/7. Thirteen independent behavioral reverts fail across +review command passes 7/7. Seventeen independent behavioral reverts fail across the feature and both review rounds; restoring the implementations passes. A separate local full-suite attempt hit the unchanged 300-second HTTP crash-drill @@ -233,3 +258,11 @@ the source-verification run passes all three complete gates with every original resource assertion retained. Fresh-clone strict tracker health passes with merge drivers and isolated Git configuration. Existing telemetry and provenance advisories remain, and all tracker histories preserve their main-branch prefix. + +The subsequent full review of `39e6c5e` adds supported meta lease takeover and +separate inner-promotion headroom, as specified above. Four new behavioral +reverts fail independently: dropping force forwarding, restoring loop-resume +guidance, restoring the old reservation function, and removing the specific +promotion-budget refusal check. Restored linked regressions pass 4/4 and the +complete meta suite passes 22/22. The complete npm/Bun release matrix must rerun +for these changes; the preceding 617-test result is not a passing claim for them. diff --git a/examples/meta-approval.md b/examples/meta-approval.md index 28eb0de4..f871fd81 100644 --- a/examples/meta-approval.md +++ b/examples/meta-approval.md @@ -4,6 +4,9 @@ This example grants one two-generation search with two candidates per generation The outer controller reserves its declared worst-case plan once. Inner process fits reserve and settle their measured resources under this same Decision. Proposal calls include local model inventory and inference requests. +The separate promotion allowance covers all five possible inner fits at the +declared maximum of two steps each. Its headroom remains reserved across resume; +promotions already consumed by those fits are not charged again. ```json { diff --git a/index.ts b/index.ts index 8aed71c9..9cca6b8f 100644 --- a/index.ts +++ b/index.ts @@ -1949,11 +1949,11 @@ async function buildAncestry(client: PmClient, headId: string, strict: boolean): } /** - * Count promoted generations that recorded a given approval item as their + * List promoted generation identities that recorded a given approval item as their * authorization. * - * This is only called on the promotion path, where the approved budget cannot be - * established while any Generation is uncountable. A Generation whose body has + * Promotion and reservation accounting cannot establish the approved budget + * while any Generation is uncountable. A Generation whose body has * no JSON fence or whose spec fails to parse is therefore refused rather than * skipped: treating unreadable provenance as absent provenance inverts the * contract, since the budget exists to bound a recursive loop that promotes @@ -1964,16 +1964,16 @@ async function buildAncestry(client: PmClient, headId: string, strict: boolean): * * @param client - Client bound to the workspace holding the generations. * @param approvalId - Approval Decision item whose consumed budget is counted. - * @returns The number of generations promoted under this approval. + * @returns Canonical ids of generations promoted under this approval, without exposing their bodies. * @throws When any generation's specification cannot be read or parsed. */ -async function countPromotedUnderApproval(client: PmClient, approvalId: string): Promise { - // Bodies come back with the listing. This runs inside the promotion's writer +export async function promotedGenerationIdsUnderApproval(client: PmClient, approvalId: string): Promise { + // Bodies come back with the listing. Callers hold the SDK writer // lock, so a per-record `client.get` would make the critical section grow one // read per historical generation, and a large enough lineage would turn a // correct refusal into a lock-wait timeout for every concurrent promoter. const result = await client.list({ type: "Generation", status: "all", noTruncate: true, fields: "id,body" }); - let count = 0; + const promoted: string[] = []; for (const item of result.items) { // The SDK types a listed item's `id` as optional; a record without one // carries no identity to report, so it is skipped rather than counted. @@ -1989,9 +1989,9 @@ async function countPromotedUnderApproval(client: PmClient, approvalId: string): } catch (error) { fail(`Promotion refused: generation ${item.id} has an unparseable specification (${String(error)}), so the approved budget cannot be established.`, "budget_undecidable", EXIT_CODE.CONFLICT); } - if (spec.promoted && spec.approval === approvalId) count += 1; + if (spec.promoted && spec.approval === approvalId) promoted.push(item.id); } - return count; + return promoted; } @@ -2459,7 +2459,7 @@ async function promoteGenerationCore(client: PmClient, coordinates: WorkspaceCoo // is a comparison between two values, and re-reading only one of them // leaves the comparison stale in the other direction. const lockedApprovalSpec = await readApprovalSpec(client, approvalId); - promotedCount = await countPromotedUnderApproval(client, approvalId); + promotedCount = (await promotedGenerationIdsUnderApproval(client, approvalId)).length; permittedPromotions = lockedApprovalSpec.permitted_promotions; if (promotedCount >= permittedPromotions) { fail(`Advancing past the approved promotion budget is refused. ${promotedCount} promotion(s) consumed; approval ${approvalId} permits ${permittedPromotions}. Extend approval item ${approvalId} to authorize more promotions.`, "budget_exceeded", EXIT_CODE.CONFLICT); @@ -2803,10 +2803,11 @@ async function controllerMutex(root: string, id: string, author: string, start: * @param coordinates - Workspace root and author for the lease and the claim. * @param request - Loop identity, approval and explicit operator recovery choice. * @param seedId - The seed generation item id the claim is recorded on. + * @param recovery - Supported outer command and existing audit item for a meta lease, including before its first receipt. * @returns The lease, which the caller must release exactly once. * @throws An expected `loop_controller_active` refusal when a live controller holds the lease. */ -async function acquireControllerLease(client: PmClient, coordinates: WorkspaceCoordinates, request: RlLoopRequest, seedId: string): Promise { +async function acquireControllerLease(client: PmClient, coordinates: WorkspaceCoordinates, request: RlLoopRequest, seedId: string, recovery?: { readonly command: string; readonly auditItem: string }): Promise { const id = request.id; // Git worktrees share the repository metadata, so the SDK's lease and // launch journal are shared even when the tracked PM roots diverge. @@ -2821,7 +2822,7 @@ async function acquireControllerLease(client: PmClient, coordinates: WorkspaceCo } const lockId = loopLeaseLockId(id); const lockPath = join(authorityRoot, "locks", `${lockId}.lock`); - const refusal = `Lease ${relative(coordinates.pmRoot, lockPath)}; operator recovery: pm rl loop resume ${id} --approval ${request.approval} --force-takeover.`; + const refusal = `Lease ${relative(coordinates.pmRoot, lockPath)}; operator recovery: ${recovery?.command ?? `pm rl loop resume ${id} --approval ${request.approval} --force-takeover`}.`; const ownStart = loopProcessStartTime(process.pid, process.platform, request.processIdentityIO); if (ownStart === null) { fail(`Loop ${id} cannot acquire a lease without a verifiable process start time. Restore OS process-start tooling or access before retrying; --force-takeover cannot bypass unavailable controller identity. ${refusal}`, "loop_identity_unavailable", EXIT_CODE.CONFLICT); @@ -2854,7 +2855,7 @@ async function acquireControllerLease(client: PmClient, coordinates: WorkspaceCo } if (request.forceTakeover === true) { // Host and owner digests identify the previous holder without publishing machine identity. - await client.update(seedId, { comment: [`Loop ${id} forced lease takeover by ${coordinates.author}: ${JSON.stringify({ + await client.update(recovery?.auditItem ?? seedId, { comment: [`Loop ${id} forced lease takeover by ${coordinates.author}: ${JSON.stringify({ previous_holder: { pid: typeof record["pid"] === "number" ? record["pid"] : null, process_start_time_digest: hashJson(String(record["process_start_time"])), hostname_digest: hashJson(String(record["hostname"])), owner_digest: hashJson(String(record["owner"])) }, lock: relative(coordinates.pmRoot, lockPath), @@ -3277,9 +3278,10 @@ async function durableLoopStep(client: PmClient, lease: ControllerLease, id: str /** Durable step executor shared by inner and outer controllers. */ export type RlDurableStep = (key: string, input: JsonValue, execute: () => Promise) => Promise; -/** Reuse the inner loop's owner lease, worktree authority, phase fencing and digested receipts for recipe search. */ -export async function withRlController(client: PmClient, coordinates: WorkspaceCoordinates, id: string, signal: AbortSignal, execute: (step: RlDurableStep) => Promise): Promise { - const lease = await acquireControllerLease(client, coordinates, { id, approval: "meta", config: null, signal }, `${id}-step-programme`); +/** Reuse the inner lease and fenced receipts with the real approval, supported recovery command and audited operator override. */ +export async function withRlController(client: PmClient, coordinates: WorkspaceCoordinates, request: Pick & { readonly recoveryCommand: string }, signal: AbortSignal, execute: (step: RlDurableStep) => Promise): Promise { + const { id } = request; + const lease = await acquireControllerLease(client, coordinates, { ...request, config: null, signal }, `${id}-step-programme`, { command: request.recoveryCommand, auditItem: request.approval }); try { return await execute(async (key, input, operation) => { signal.throwIfAborted(); @@ -4180,6 +4182,7 @@ async function runMetaCommand(context: CommandHandlerContext): Promise }> { +async function metaApproval(client: PmClient, id: string): Promise<{ id: string; digest: string; limits: Record; promotions: number }> { const item = await readCompleteLoopItem(client, id); assert.equal(item.item.type, "Decision", "meta_approval_required"); const fence = /```json\n([\s\S]+?)\n```/.exec(String(item.item.body)); @@ -90,14 +93,16 @@ async function metaApproval(client: PmClient, id: string): Promise<{ id: string; for (const key of ["training_samples", "proposal_calls", "recipe_promotions"]) { assert.ok(Number.isSafeInteger(spec.meta_budget[key]) && spec.meta_budget[key] >= 0, "meta_budget_bound"); } - return { id: String(item.item.id), digest: hashJson(spec as unknown as JsonValue), limits: spec.meta_budget }; + const promotions = parseApprovalSpec(fence[1], "Meta approval").permitted_promotions; + assert.ok(Number.isSafeInteger(promotions), "meta_promotion_budget_bound"); + return { id: String(item.item.id), digest: hashJson(spec as unknown as JsonValue), limits: spec.meta_budget, promotions }; } /** Parse reservation envelopes independent of JSON spacing; unrelated text cannot charge or conceal an allowance. */ -export function metaReservation(body: string): { id: string; approval: string; charge: Record } | null { +export function metaReservation(body: string): { id: string; approval: string; charge: Record; promotion_headroom: number } | null { if (!body.includes("pm-rl/meta-reservation/1")) return null; try { - const record = JSON.parse(body) as { format: string; id: string; approval: string; charge: Record }; + const record = JSON.parse(body) as { format: string; id: string; approval: string; charge: Record; promotion_headroom: number }; return record.format === "pm-rl/meta-reservation/1" ? record : null; } catch { return null; } } @@ -116,24 +121,27 @@ async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, re const { config } = request; const charge = { training_samples: (1 + config.meta_generations * config.candidates) * RECIPE_BOUNDS.steps[1] * RECIPE_BOUNDS.batch[1], proposal_calls: request.proposer === "decision-model" ? 2 * config.meta_generations : 0, recipe_promotions: config.meta_generations }; + const promotionHeadroom = (1 + config.meta_generations * config.candidates) * RECIPE_BOUNDS.steps[1]; const key = `${request.id}-reservation`; await commitProcessTransaction({ ...coordinates, transactionId: `${key}-reserve`, steps: [{ id: "reserve", async inspect() { const previous = await readMetaReceipt(client, key); if (previous === null) return { state: "pending" }; assert.equal(previous.item.type, "Decision", "meta_reservation_drift"); - const record = JSON.parse(String(previous.item.body)) as { format: string; id: string; binding: string; approval: string; charge: JsonValue }; + const record = JSON.parse(String(previous.item.body)) as { format: string; id: string; binding: string; approval: string; charge: JsonValue; promotion_headroom: number }; assert.equal(record.binding, binding, "meta_reservation_drift"); assert.equal(record.format, "pm-rl/meta-reservation/1", "meta_reservation_drift"); assert.equal(record.id, key, "meta_reservation_drift"); assert.equal(record.approval, (await metaApproval(client, request.approval)).id, "meta_reservation_drift"); assert.equal(hashJson(record.charge), hashJson(charge), "meta_reservation_drift"); + assert.equal(record.promotion_headroom, promotionHeadroom, "meta_reservation_drift"); return { state: "applied" }; }, async apply() { const approval = await metaApproval(client, request.approval); const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); const charges: Record[] = []; + const promotions: { prefix: string; headroom: number; consumed: number }[] = []; for (const item of items.items.filter((entry) => entry.type === "Decision" && entry.id.endsWith("-reservation"))) { const record = metaReservation(String((await readCompleteLoopItem(client, item.id)).item.body)); if (record === null) continue; @@ -143,13 +151,25 @@ async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, re assert.ok(Number.isSafeInteger(record.charge[key]) && record.charge[key] >= 0, "meta_reservation_charge"); } charges.push(record.charge); + assert.ok(Number.isSafeInteger(record.promotion_headroom) && record.promotion_headroom >= 0, "meta_promotion_reservation_charge"); + promotions.push({ prefix: item.id.slice(0, -"-reservation".length), headroom: record.promotion_headroom, consumed: 0 }); } } for (const key of ["training_samples", "proposal_calls", "recipe_promotions"] as const) { const total = charges.reduce((sum, entry) => sum + entry[key], charge[key]); assert.ok(Number.isSafeInteger(total) && total <= approval.limits[key], `meta_budget_exhausted: ${key}`); } - await client.create({ id: key, type: "Decision", title: "Reserved bounded recipe search", body: JSON.stringify({ format: "pm-rl/meta-reservation/1", id: key, binding, approval: approval.id, charge }) }); + let unreserved = 0; + const consumed = items.items.some((item) => item.type === "Generation") ? await promotedGenerationIdsUnderApproval(client, approval.id) : []; + for (const id of consumed) { + const reserved = promotions.find(({ prefix }) => id.startsWith(`${prefix}-`) && /^-(?:initial|m(?:[1-9]|10)-c[0-7])-g[12]$/.test(id.slice(prefix.length))); + if (reserved === undefined) unreserved += 1; + else reserved.consumed += 1; + } + for (const reserved of promotions) assert.ok(reserved.consumed <= reserved.headroom, "meta_promotion_reservation_exceeded"); + const totalPromotions = promotions.reduce((sum, reserved) => sum + reserved.headroom, promotionHeadroom + unreserved); + assert.ok(Number.isSafeInteger(totalPromotions) && totalPromotions <= approval.promotions, "meta_promotion_budget_exhausted"); + await client.create({ id: key, type: "Decision", title: "Reserved bounded recipe search", body: JSON.stringify({ format: "pm-rl/meta-reservation/1", id: key, binding, approval: approval.id, charge, promotion_headroom: promotionHeadroom }) }); }, // Conservative reservations survive transaction recovery and are never refunded by search itself. async compensate() {}, @@ -239,7 +259,8 @@ export async function runRlMeta(client: PmClient, coordinates: ProcessCoordinate const input = { format: "pm-rl/meta-programme/1", id: request.id, config: config as unknown as JsonValue, dataset: environment.digest, approval_id: approval.id, approval: approval.digest, proposer: request.proposer, endpoint: request.decisionEndpoint ?? "http://127.0.0.1:11434" }; const binding = hashJson(input); - return withRlController(client, coordinates, request.id, signal, async (durable) => { + const recoveryCommand = `pm rl meta run ${request.id} --file --dataset --approval ${request.approval} --proposer ${request.proposer} --force-takeover`; + return withRlController(client, coordinates, { id: request.id, approval: request.approval, forceTakeover: request.forceTakeover, recoveryCommand }, signal, async (durable) => { /** Verify approval identity at every boundary, and notify observers only after the receipt is durable. */ const step: RlDurableStep = async (key, value, execute) => { assert.equal((await metaApproval(client, request.approval)).digest, approval.digest, "meta_budget_drift"); diff --git a/test/meta.test.ts b/test/meta.test.ts index 27dc5cbc..ebf9122d 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -5,10 +5,11 @@ import { once } from "node:events"; import { fork } from "node:child_process"; import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs"; import { join } from "node:path"; +import { hostname } from "node:os"; import { test } from "node:test"; import { createExtensionTestHarness } from "@unbrained/pm-cli/sdk/testing"; -import { certifyCompleteListResult } from "@unbrained/pm-cli/sdk/runtime"; -import extension, { hashJson, withRlController, type JsonValue, type RlCommandResult, loopLeaseLockId } from "../index.ts"; +import { acquireLock, certifyCompleteListResult } from "@unbrained/pm-cli/sdk/runtime"; +import extension, { hashJson, runRlLoop, promotedGenerationIdsUnderApproval, type JsonValue, type RlCommandResult, loopLeaseLockId, loopProcessStartTime, LOOP_LEASE_TTL_SECONDS, RL_COMMANDS } from "../index.ts"; import { compareRecipes, durableRecipeProposals, metaReservation, parseMetaConfig, proposeRecipes, recipeExamples, recipeSuccessor, runRlMeta, scoreTrackerPolicy, type MetaConfig, type MetaRequest } from "../meta.ts"; import { INITIAL_RECIPE, recipeArtifact, seededRecipes } from "../recipe.ts"; import { banditCheckpoint } from "../bandit.ts"; @@ -24,6 +25,129 @@ function requestFor(workspace: Awaited>, id: st return { id, config, dataset: workspace.dataset, approval: workspace.approval, proposer: "seeded" }; } +test("ambiguous outer meta leases expose working CLI takeover and preserve live-holder refusals", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const id = "meta-recovery"; + const request = requestFor(w, id, { ...metaConfig, meta_generations: 1, candidates: 1 }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, onStep(key) { if (key === "programme") throw new Error("programme reserved"); } }), /programme reserved/); + const file = join(w.root, "recovery.json"); writeFileSync(file, JSON.stringify(request.config)); + const path = join(w.coordinates.pmRoot, "locks", `${loopLeaseLockId(id)}.lock`); + const harness = await createExtensionTestHarness(extension, { name: "pm-rl", capabilities: ["commands", "hooks", "schema"] }); + const command = RL_COMMANDS.find((command) => command.name === "rl meta run")!; + assert.ok("flags" in command && command.flags.some((flag) => flag.long === "--force-takeover")); + for (const option of ["force_takeover", "forceTakeover"] as const) { + const release = await acquireLock(w.coordinates.pmRoot, loopLeaseLockId(id), LOOP_LEASE_TTL_SECONDS, "synthetic-foreign-holder"); + try { + const original = JSON.parse(readFileSync(path, "utf8")) as Record; + writeFileSync(path, JSON.stringify({ ...original, hostname: "other-host.invalid" })); + await assert.rejects(runRlMeta(w.client, w.coordinates, request), (error: unknown) => { + const message = String(error); assert.match(message, /holder is ambiguous/); + assert.ok(message.includes(`pm rl meta run ${id} --file --dataset --approval ${w.approval} --proposer seeded --force-takeover`)); + assert.ok(!message.includes("rl loop resume")); return true; + }); + const recovered = await harness.runCommand({ command: "rl meta run", pmRoot: w.coordinates.pmRoot, args: [id], + options: { file, dataset: w.dataset, approval: w.approval, [option]: true }, global: { author: "operator-test" } }); + assert.equal(recovered.handled, true, recovered.errorMessage ?? "meta takeover must succeed"); + assert.equal((recovered.result as RlCommandResult).action, "rl-meta-run"); + } finally { await release(); } + } + const fresh = "fresh-recovery"; + const freshPath = join(w.coordinates.pmRoot, "locks", `${loopLeaseLockId(fresh)}.lock`); + const releaseFresh = await acquireLock(w.coordinates.pmRoot, loopLeaseLockId(fresh), LOOP_LEASE_TTL_SECONDS, "synthetic-unpublished-holder"); + try { + const original = JSON.parse(readFileSync(freshPath, "utf8")) as Record; + writeFileSync(freshPath, JSON.stringify({ ...original, hostname: "other-host.invalid" })); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, id: fresh, forceTakeover: true, + onStep(key) { if (key === "programme") throw new Error("fresh takeover reserved"); } }), /fresh takeover reserved/); + } finally { await releaseFresh(); } + const history = readFileSync(join(w.coordinates.pmRoot, "history", `${w.approval}.jsonl`), "utf8"); + assert.ok(history.includes("forced lease takeover by operator-test")); + assert.ok(history.includes(`Loop ${fresh} forced lease takeover`)); + assert.ok(history.includes("hostname_digest")); assert.ok(!history.includes("other-host.invalid")); + assert.ok(!history.includes(hostname())); assert.ok(!history.includes(w.coordinates.pmRoot)); + const jobs = await listProcessJobs(w.client); + for (const state of ["alive", "unverifiable"] as const) { + const release = await acquireLock(w.coordinates.pmRoot, loopLeaseLockId(id), LOOP_LEASE_TTL_SECONDS, "synthetic-local-holder"); + try { + const original = JSON.parse(readFileSync(path, "utf8")) as Record; + const contents = JSON.stringify({ ...original, hostname: hostname(), process_start_time: state === "alive" ? loopProcessStartTime(process.pid) : undefined }); + writeFileSync(path, contents); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, forceTakeover: true }), new RegExp(`holder is ${state}`)); + assert.equal(readFileSync(path, "utf8"), contents); + } finally { await release(); } + } + assert.deepEqual(await listProcessJobs(w.client), jobs, "terminal recovery and blocked holders cannot launch extra fits"); +}); + +test("shared inner promotion headroom refuses before training and reserves atomically once", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const config = { ...metaConfig, meta_generations: 1, candidates: 1 }; + for (const permitted of [0, 3]) { + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: permitted })}\n\`\`\`` }); + await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, `low-${permitted}`, config)), /meta_promotion_budget_exhausted/); + assert.equal((await listProcessJobs(w.client)).length, 0); + } + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: 4 })}\n\`\`\`` }); + const outcomes = await Promise.allSettled(["capacity-one", "capacity-two"].map((id) => runRlMeta(w.client, w.coordinates, { + ...requestFor(w, id, config), onStep(key) { if (key === "programme") throw new Error("headroom held"); }, + }))); + const reasons = outcomes.map((outcome) => String((outcome as PromiseRejectedResult).reason)); + assert.equal(reasons.filter((reason) => reason.includes("headroom held")).length, 1, reasons.join("\n")); + assert.equal(reasons.filter((reason) => reason.includes("meta_promotion_budget_exhausted")).length, 1, reasons.join("\n")); + const [reservation] = certifyCompleteListResult(await w.client.listAllComplete({ includeBody: false })).items.filter((item) => item.id.endsWith("-reservation")); + const body = String((await w.client.get(reservation.id)).item.body); + assert.equal((JSON.parse(body) as { promotion_headroom: number }).promotion_headroom, 4); + const id = reasons[0].includes("headroom held") ? "capacity-one" : "capacity-two"; + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, id, config), onStep() { throw new Error("same headroom adopted"); } }), /same headroom adopted/); + assert.equal(String((await w.client.get(reservation.id)).item.body), body); + for (const promotion_headroom of [undefined, -1, 0.5, Number.MAX_SAFE_INTEGER + 1]) { + await w.client.update(reservation.id, { body: JSON.stringify({ ...JSON.parse(body), promotion_headroom }) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "bad-capacity", config)), /meta_promotion_reservation_charge/); + } +}); + +test("promotion headroom counts outside usage without charging reserved promotions twice", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const config = { ...metaConfig, meta_generations: 1, candidates: 1 }; + const raw = JSON.parse(readFileSync(new URL("../examples/loop-bandit.json", import.meta.url), "utf8")) as Record; + const loop = { ...raw, max_generations: 1 }; + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: 8 })}\n\`\`\`` }); + const stop = (key: string) => { if (key === "programme") throw new Error("capacity reserved"); }; + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, "first-capacity", config), onStep: stop }), /capacity reserved/); + for (const id of ["first-capacity-initial", "first-capacity-other"]) { + const report = await runRlLoop(w.client, w.coordinates, { id, config: loop, approval: w.approval }); + assert.equal(report.promoted, 1, "real numerical generations must consume promotion capacity"); + } + const ids = await promotedGenerationIdsUnderApproval(w.client, w.approval); + assert.equal(ids.length, 2); + await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "outside-counted", config)), /meta_promotion_budget_exhausted/); + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: 9 })}\n\`\`\`` }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, "second-capacity", config), onStep: stop }), /capacity reserved/); + await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "third-capacity", config)), /meta_promotion_budget_exhausted/); + const second = await w.client.get("second-capacity-reservation"); + await w.client.update(second.item.id, { body: JSON.stringify({ ...JSON.parse(String(second.item.body)), promotion_headroom: 0 }) }); + const first = await w.client.get("first-capacity-reservation"); + await w.client.update(first.item.id, { body: JSON.stringify({ ...JSON.parse(String(first.item.body)), promotion_headroom: 0 }) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "overdrawn", config)), /meta_promotion_reservation_exceeded/); +}); + +test("inner promotion-budget refusals never become recipe evidence, including after an accepted generation", { timeout: 600_000 }, async () => { + for (const permitted of [0, 1]) { + const w = await metaWorkspace(); + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: permitted })}\n\`\`\`` }); + const recipe = recipeArtifact({ ...metaConfig.initial_recipe.knobs, steps: 2 }); + const environment = openTrackerEnvironment(w.client, w.coordinates, w.dataset, metaConfig, w.approval); + await assert.rejects(environment.fit(recipe, "budget-fit", new AbortController().signal), /meta_inner_promotion_budget/); + assert.equal((await promotedGenerationIdsUnderApproval(w.client, w.approval)).length, permitted); + const generation = await w.client.get(`budget-fit-g${permitted + 1}`); + const comments = await w.client.comments(generation.item.id, { outputBudget: "unbounded", outputLimit: "unbounded" }); + assert.ok("comments" in comments); + const index = comments.comments.findIndex((comment) => comment.text.includes("approved promotion budget")); + assert.ok(index >= 0); + // Replay a different intentional refusal through real SDK history; it must not be classified as budget exhaustion. + await w.client.comments(generation.item.id, { edit: index + 1, add: `Loop budget-fit generation ${permitted + 1} promotion refused: Promotion refused: the evaluation set is reachable from the candidate's training data.` }); + const policy = await environment.fit(recipe, "budget-fit", new AbortController().signal); + assert.equal(policy.weight === 0, permitted === 0); + } +}); + test("meta programme bounds and search domains cannot tune the statistical gate or trainer command", () => { assert.deepEqual(parseMetaConfig(metaConfig), metaConfig); for (const key of ["seed", "meta_generations", "candidates", "timeout_ms", "evaluation_samples"] as const) { @@ -184,7 +308,7 @@ test("canonical reservation lookup ignores another programme's suffixed receipt const w = await metaWorkspace(); const foreign = await w.client.create({ id: "a-victim-reservation", type: "Decision", title: "Other programme reservation", body: JSON.stringify({ format: "pm-rl/meta-reservation/1", id: "a-victim-reservation", binding: "other-programme", approval: w.approval, - charge: { training_samples: 0, proposal_calls: 0, recipe_promotions: 0 }, + charge: { training_samples: 0, proposal_calls: 0, recipe_promotions: 0 }, promotion_headroom: 0, }) }); const foreignBody = String((await w.client.get(foreign.item.id)).item.body); const request = { ...requestFor(w, "victim", { ...metaConfig, meta_generations: 1, candidates: 1 }), @@ -269,7 +393,7 @@ test("an interrupted atomic search reservation is retained once, including drift const item = await w.client.get("transaction-reservation"); const original = JSON.parse(String(item.item.body)) as { charge: Record }; await w.client.update(item.item.id, { body: JSON.stringify({ ...original, binding: "changed" }) }); await assert.rejects(runRlMeta(w.client, w.coordinates, request), /meta_reservation_drift/); - for (const patch of [{ format: "foreign" }, { id: "foreign" }, { approval: "foreign" }, { charge: { ...original.charge, proposal_calls: 1 } }]) { + for (const patch of [{ format: "foreign" }, { id: "foreign" }, { approval: "foreign" }, { charge: { ...original.charge, proposal_calls: 1 } }, { promotion_headroom: 0 }]) { await w.client.update(item.item.id, { body: JSON.stringify({ ...original, ...patch }) }); await assert.rejects(runRlMeta(w.client, w.coordinates, request), /meta_reservation_drift/); } @@ -292,7 +416,7 @@ test("programme identity cannot hide approval reservations through SDK case fold assert.equal(certifyCompleteListResult(await w.client.listAllComplete({ includeBody: false })).items.length, 1, "invalid identities leave only the approval"); await w.client.create({ id: "LEGACY-reservation", type: "Decision", title: "Retained case-folded allocation", body: JSON.stringify({ format: "pm-rl/meta-reservation/1", id: "LEGACY-reservation", approval: w.approval, - charge: { training_samples: 1024, proposal_calls: 0, recipe_promotions: 1 }, + charge: { training_samples: 1024, proposal_calls: 0, recipe_promotions: 1 }, promotion_headroom: 4, }) }); await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, onStep() { throw new Error("retained allocation was hidden"); } }), /meta_budget_exhausted/); }); diff --git a/tracker-environment.ts b/tracker-environment.ts index 1094b026..d73a3720 100644 --- a/tracker-environment.ts +++ b/tracker-environment.ts @@ -107,6 +107,7 @@ async function fitRecipe(client: PmClient, coordinates: ProcessCoordinates, requ adapter: config.adapter as unknown as JsonValue, } }); assert.ok(!["process_failed", "process_cancelled", "process_invalidated", "wall_limit_exceeded", "checkpoint_limit_exceeded"].includes(report.stop_reason), "meta_inner_failed"); + assert.ok(!(report.stop_reason === "promotion_refused" && /approved promotion budget/.test(String(report.refusal_reason))), "meta_inner_promotion_budget"); let weight = 0; const accepted = report.generations.filter((generation) => generation.promoted).at(-1); if (accepted !== undefined) { From f491e1980ef9cdf979e5f23b5db2c5e70161f162 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:36:39 +0200 Subject: [PATCH 15/24] docs: record meta recovery and promotion budget verification --- .agents/pm/features/pm-rl-meta.toon | 7 +++---- .agents/pm/history/pm-rl-meta.jsonl | 2 ++ RECURSIVE_TRAINING.md | 2 +- docs/meta-recursive.md | 15 +++++++++------ 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index f88d6b2d..bc4c8259 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T12:17:47.381Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T12:36:36.367Z" author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[39]{created_at,author,text}: +comments[40]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -52,6 +50,7 @@ comments[39]{created_at,author,text}: "2026-10-18T11:57:45.340Z",codex-agent,"New full CodeRabbit review of 39e6c5e has two unresolved findings: unsupported recovery guidance/options for ambiguous outer meta leases, and missing shared inner-promotion headroom plus swallowed promotion-budget refusal. Read both threads and the complete newest review body; zero open GitHub issue findings. The branch is clean, ahead of main and not behind. Reusing this feature item for supported operator recovery and fail-closed promotion accounting with real tracker regressions and behavioral revert proofs. Prior acceptance receipts and statistical thresholds remain unchanged." "2026-10-18T12:15:15.766Z",codex-agent,"Both new review findings are implemented. MetaRequest and the public command forward force takeover and the actual approval; refusals name the supported meta run command with file, dataset, approval and proposer options. A digest-only holder audit goes to the existing approval before replacing the lease, including before the first programme receipt. Verified live and unverifiable holders still refuse. Shared promotion headroom is (1 + meta_generations * candidates) times the maximum declared recipe steps, stored separately from meta_budget and checked atomically against permitted_promotions. Canonical reserved namespaces consume held headroom once; outside promotions count separately. Core accounting exposes only promoted ids, never Generation bodies or held-out examples, to search. Inner promotion_refused reports specifically naming the approved promotion budget throw meta_inner_promotion_budget, including after an accepted prior generation; non-budget refusal replay remains allowed. Full meta suite passed 22/22; build, test compilation, lint, duplicates and docs gates pass with 35 sources and 295 declarations. Four isolated behavioral reverts each fail 0/1: remove only force forwarding, restore only inner-loop refusal guidance, restore only the old reserveMeta function, or remove only the budget-refusal guard. Every fixed source is restored. The complete feature now has seventeen revert proofs. Pinned SDK rejects a Generation type filter before that custom type exists; certified metadata establishes an empty inventory without changing schema or swallowing read errors. Registry CLI is 2026.10.18; the repo SDK pin remains 2026.10.13." "2026-10-18T12:17:47.381Z",codex-agent,"Restored PM-linked review command passes 4/4, zero failures/cancellations/skips, using the repository-pinned CLI with explicit author. The outside-consumption regression includes another loop sharing the reservation prefix but outside its canonical inner namespace, so a broad prefix cannot hide consumed promotions. The full meta suite passed 22/22 and the focused linked run also covers the final pre-publication audit target. Result persistence remains disabled by project policy, so this comment records the receipt. Previous complete release CI on 39e6c5e passed 617/617 in all three variants; the new source has 621 tests and will be checked by both complete commands with isolated HOME/Git identity. No new passing full-gate result is claimed yet. Live and sanity receipts, the promotion criterion, dependency pins and releases remain unchanged." + "2026-10-18T12:36:35.608Z",codex-agent,"Source-verification CI run 39126701196 on 268d04a9fdd22960a78d9d675a6c342f29153c74 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 621/621, zero failures/cancellations/skips, 100/100/100/100 statements/lines/branches/functions across all 35 declared sources and 295 documented declarations. Identity, publish attestation, production audit, packaging and changelog checks pass; CodeQL passes. Full meta suite 22/22 and PM-linked review regressions 4/4 pass. Four independent new behavioral reverts fail 0/1 each and fixed sources are restored, bringing the total to seventeen. CodeRabbit inspected both fixes at this source head, explicitly did not execute tests, and resolved both threads itself. No author resolution request was made. Zero open GitHub issue findings. Fresh no-local clone strict health passes with installed merge drivers and isolated Git identity; existing advisory warnings remain and tracker history is append-only. Main is unchanged, source worktree is clean, live/sanity receipts and thresholds are unchanged, and releases remain disabled. The final documentation/claim-release commit will receive an exact-head matrix rerun before handoff; no merge or close is performed." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index a65fb4a8..9f79fd21 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -71,3 +71,5 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T12:15:15.766Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/37","value":{"created_at":"2026-10-18T12:15:15.766Z","author":"codex-agent","text":"Both new review findings are implemented. MetaRequest and the public command forward force takeover and the actual approval; refusals name the supported meta run command with file, dataset, approval and proposer options. A digest-only holder audit goes to the existing approval before replacing the lease, including before the first programme receipt. Verified live and unverifiable holders still refuse. Shared promotion headroom is (1 + meta_generations * candidates) times the maximum declared recipe steps, stored separately from meta_budget and checked atomically against permitted_promotions. Canonical reserved namespaces consume held headroom once; outside promotions count separately. Core accounting exposes only promoted ids, never Generation bodies or held-out examples, to search. Inner promotion_refused reports specifically naming the approved promotion budget throw meta_inner_promotion_budget, including after an accepted prior generation; non-budget refusal replay remains allowed. Full meta suite passed 22/22; build, test compilation, lint, duplicates and docs gates pass with 35 sources and 295 declarations. Four isolated behavioral reverts each fail 0/1: remove only force forwarding, restore only inner-loop refusal guidance, restore only the old reserveMeta function, or remove only the budget-refusal guard. Every fixed source is restored. The complete feature now has seventeen revert proofs. Pinned SDK rejects a Generation type filter before that custom type exists; certified metadata establishes an empty inventory without changing schema or swallowing read errors. Registry CLI is 2026.10.18; the repo SDK pin remains 2026.10.13."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:15:15.766Z"}],"before_hash":"80618012595dd11543cefa45e4712d08087a6b9da1c27f506c6a7c9e1d3dea55","after_hash":"4afab43ba88b6d1089e9d01cc5a0c523a92429e0f914c86125c3f7ffa83ed1d3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f15484a3927041d34674d7b872066826774db943094d189bfce201a0d159b322"} {"hash_algorithm":"sha256","ts":"2026-10-18T12:15:16.820Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/7","value":{"command":"node --test --test-name-pattern=\"ambiguous outer meta|shared inner promotion|promotion headroom counts|inner promotion-budget\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T12:15:16.768Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:15:16.820Z"}],"before_hash":"4afab43ba88b6d1089e9d01cc5a0c523a92429e0f914c86125c3f7ffa83ed1d3","after_hash":"9f2789e259162dbcf07eeb073bf3cc0d52adb8b323295bc5c0b72972435ce760","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"e0dde2e128720e65611c9a00c4b79ead5057f5658f83a2d1055919c1bfdce4b7"} {"hash_algorithm":"sha256","ts":"2026-10-18T12:17:47.381Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/38","value":{"created_at":"2026-10-18T12:17:47.381Z","author":"codex-agent","text":"Restored PM-linked review command passes 4/4, zero failures/cancellations/skips, using the repository-pinned CLI with explicit author. The outside-consumption regression includes another loop sharing the reservation prefix but outside its canonical inner namespace, so a broad prefix cannot hide consumed promotions. The full meta suite passed 22/22 and the focused linked run also covers the final pre-publication audit target. Result persistence remains disabled by project policy, so this comment records the receipt. Previous complete release CI on 39e6c5e passed 617/617 in all three variants; the new source has 621 tests and will be checked by both complete commands with isolated HOME/Git identity. No new passing full-gate result is claimed yet. Live and sanity receipts, the promotion criterion, dependency pins and releases remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:17:47.381Z"}],"before_hash":"9f2789e259162dbcf07eeb073bf3cc0d52adb8b323295bc5c0b72972435ce760","after_hash":"9cd5abe82a012ac67822e6350c81ba6e1221d4a7dfb4077015203c74d0a268c7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e902c9bd41afbbde09b3751af655021eba6cba47d2f1ce92247b72743573677b"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:36:35.608Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/39","value":{"created_at":"2026-10-18T12:36:35.608Z","author":"codex-agent","text":"Source-verification CI run 39126701196 on 268d04a9fdd22960a78d9d675a6c342f29153c74 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 621/621, zero failures/cancellations/skips, 100/100/100/100 statements/lines/branches/functions across all 35 declared sources and 295 documented declarations. Identity, publish attestation, production audit, packaging and changelog checks pass; CodeQL passes. Full meta suite 22/22 and PM-linked review regressions 4/4 pass. Four independent new behavioral reverts fail 0/1 each and fixed sources are restored, bringing the total to seventeen. CodeRabbit inspected both fixes at this source head, explicitly did not execute tests, and resolved both threads itself. No author resolution request was made. Zero open GitHub issue findings. Fresh no-local clone strict health passes with installed merge drivers and isolated Git identity; existing advisory warnings remain and tracker history is append-only. Main is unchanged, source worktree is clean, live/sanity receipts and thresholds are unchanged, and releases remain disabled. The final documentation/claim-release commit will receive an exact-head matrix rerun before handoff; no merge or close is performed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:36:35.608Z"}],"before_hash":"9cd5abe82a012ac67822e6350c81ba6e1221d4a7dfb4077015203c74d0a268c7","after_hash":"d56fbf4ab6250ea56f8e6b1636b88fd47a6039f0c1ff1ef718c477046c6194dd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"61893124d6a02d3cc264e793debfffca1d1cea0221c7e15a06cc6141b2b66d14"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:36:36.367Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:36:36.367Z"}],"before_hash":"d56fbf4ab6250ea56f8e6b1636b88fd47a6039f0c1ff1ef718c477046c6194dd","after_hash":"9667a3b132030975cb7b7b03bae9f51caf3c9bebbfc58a009a5e1149a38f9215","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"ae2fdd4c6218c6682889c8c632c6ee111fecaef8006c327a8870b8226f2837d3"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 851907db..28c1eebf 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -88,7 +88,7 @@ Adapters report structured progress and completion evidence over a documented st result, not real-tracker improvement. No gate or real feature was weakened. [Complete release verification](https://github.com/unbraind/pm-rl/pull/84/checks) passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: - 617/617 each, zero failures/skips, all four coverage metrics 100% across all + 621/621 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared budget, conditional promotion and resource-refusal regressions pass; seventeen behaviour-only reverts fail with tests retained and restored code passes. diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index e0710f47..6be23212 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -207,11 +207,11 @@ predictions, and full disagreement. ## Release verification -The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39121554923) -on `798cfe8af45371ddec478e5b8c2e79259be0fce5` +The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39126701196) +on `268d04a9fdd22960a78d9d675a6c342f29153c74` executes `npm run release:check` on Node 22 and 26 and `bun run release:check` on Node 26 with isolated HOME and global/system Git configuration. Each passes -617/617 tests, zero failures/skips, 100% statements/lines/branches/functions over +621/621 tests, zero failures/skips, 100% statements/lines/branches/functions over all 35 declared sources, 295 documented declarations, and zero duplicate clones or production audit findings. Thresholds, dependency pins and release approval are unchanged. The live evidence names the measured production source commit; @@ -230,7 +230,7 @@ retained reservation case folding and both resource fault injectors fail; restor implementations pass. PM-linked data/recipe, crash/promotion/budget, identity and resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. The expanded review command passes 7/7. Seventeen independent behavioral reverts fail across -the feature and both review rounds; restoring the implementations passes. +the feature and subsequent review rounds; restoring the implementations passes. A separate local full-suite attempt hit the unchanged 300-second HTTP crash-drill deadline under host load and was retained as failed evidence. The required complete @@ -264,5 +264,8 @@ separate inner-promotion headroom, as specified above. Four new behavioral reverts fail independently: dropping force forwarding, restoring loop-resume guidance, restoring the old reservation function, and removing the specific promotion-budget refusal check. Restored linked regressions pass 4/4 and the -complete meta suite passes 22/22. The complete npm/Bun release matrix must rerun -for these changes; the preceding 617-test result is not a passing claim for them. +complete meta suite passes 22/22. The source-verification matrix above passes +621/621 in all three variants with all four coverage metrics at 100%. CodeRabbit +inspected both fixes at `268d04a` and resolved its own threads without executing +the tests. No author resolution request was made. The final documentation and +claim-release commit receives a separate exact-head CI verification. From d2de7dc0a4a2cbb7f4ffef33734e5f3d39e5cde6 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:50:26 +0200 Subject: [PATCH 16/24] fix: verify retained meta capacity before unfinished work --- .agents/pm/features/pm-rl-meta.toon | 11 +++++--- .agents/pm/history/pm-rl-meta.jsonl | 4 +++ RECURSIVE_TRAINING.md | 9 ++++--- docs/meta-recursive.md | 16 ++++++++--- meta.ts | 42 +++++++++++++++++------------ test/meta.test.ts | 29 +++++++++++++++++--- 6 files changed, 82 insertions(+), 29 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index bc4c8259..3060af99 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,11 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T12:36:36.367Z" +updated_at: "2026-10-18T12:50:23.568Z" +assignee: codex-agent +claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[40]{created_at,author,text}: +comments[42]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -51,6 +53,8 @@ comments[40]{created_at,author,text}: "2026-10-18T12:15:15.766Z",codex-agent,"Both new review findings are implemented. MetaRequest and the public command forward force takeover and the actual approval; refusals name the supported meta run command with file, dataset, approval and proposer options. A digest-only holder audit goes to the existing approval before replacing the lease, including before the first programme receipt. Verified live and unverifiable holders still refuse. Shared promotion headroom is (1 + meta_generations * candidates) times the maximum declared recipe steps, stored separately from meta_budget and checked atomically against permitted_promotions. Canonical reserved namespaces consume held headroom once; outside promotions count separately. Core accounting exposes only promoted ids, never Generation bodies or held-out examples, to search. Inner promotion_refused reports specifically naming the approved promotion budget throw meta_inner_promotion_budget, including after an accepted prior generation; non-budget refusal replay remains allowed. Full meta suite passed 22/22; build, test compilation, lint, duplicates and docs gates pass with 35 sources and 295 declarations. Four isolated behavioral reverts each fail 0/1: remove only force forwarding, restore only inner-loop refusal guidance, restore only the old reserveMeta function, or remove only the budget-refusal guard. Every fixed source is restored. The complete feature now has seventeen revert proofs. Pinned SDK rejects a Generation type filter before that custom type exists; certified metadata establishes an empty inventory without changing schema or swallowing read errors. Registry CLI is 2026.10.18; the repo SDK pin remains 2026.10.13." "2026-10-18T12:17:47.381Z",codex-agent,"Restored PM-linked review command passes 4/4, zero failures/cancellations/skips, using the repository-pinned CLI with explicit author. The outside-consumption regression includes another loop sharing the reservation prefix but outside its canonical inner namespace, so a broad prefix cannot hide consumed promotions. The full meta suite passed 22/22 and the focused linked run also covers the final pre-publication audit target. Result persistence remains disabled by project policy, so this comment records the receipt. Previous complete release CI on 39e6c5e passed 617/617 in all three variants; the new source has 621 tests and will be checked by both complete commands with isolated HOME/Git identity. No new passing full-gate result is claimed yet. Live and sanity receipts, the promotion criterion, dependency pins and releases remain unchanged." "2026-10-18T12:36:35.608Z",codex-agent,"Source-verification CI run 39126701196 on 268d04a9fdd22960a78d9d675a6c342f29153c74 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 621/621, zero failures/cancellations/skips, 100/100/100/100 statements/lines/branches/functions across all 35 declared sources and 295 documented declarations. Identity, publish attestation, production audit, packaging and changelog checks pass; CodeQL passes. Full meta suite 22/22 and PM-linked review regressions 4/4 pass. Four independent new behavioral reverts fail 0/1 each and fixed sources are restored, bringing the total to seventeen. CodeRabbit inspected both fixes at this source head, explicitly did not execute tests, and resolved both threads itself. No author resolution request was made. Zero open GitHub issue findings. Fresh no-local clone strict health passes with installed merge drivers and isolated Git identity; existing advisory warnings remain and tracker history is append-only. Main is unchanged, source worktree is clean, live/sanity receipts and thresholds are unchanged, and releases remain disabled. The final documentation/claim-release commit will receive an exact-head matrix rerun before handoff; no merge or close is performed." + "2026-10-18T12:42:18.761Z",codex-agent,"Final self-check identified a resume edge in the new headroom contract: a completed outer programme receipt skips reserveMeta, so a pending inner phase can run after the retained reservation loses promotion_headroom. Adding a real tracker regression that interrupts after programme completion, removes or damages retained capacity, and requires refusal before any process job. Retained capacity must be revalidated inside the owner-fenced execution of every unfinished phase; cached completed reports remain read-only. The preceding 621-test source verification remains valid for its exact head, but handoff waits for this additional regression and full gates." + "2026-10-18T12:50:23.567Z",codex-agent,"Retained-capacity regression reproduced the completed-programme replay gap on f491e19: 0/1 with Missing expected rejection. The fix verifies the exact retained allocation inside the owner-fenced execution callback for every unfinished phase; missing records are refused rather than recreated, and cached completed reports remain read-only. The test removes promotion_headroom, understates it, and removes the real reservation file; every case refuses before a process job. Restoring valid evidence resumes and replays without another charge or launch. Removing only the new guarded verification fails 0/1 with the test retained; restoring it passes 1/1. Exact command: node --test --test-name-pattern=\"unfinished meta phases revalidate\" test/meta.test.ts. Full node --test test/meta.test.ts now passes 23/23 through pm test --run --progress, zero failures/cancellations/skips. Build, test typecheck, lint, duplicates and docstrings pass at 35 sources and 295 declarations. This is the fifth new review-round revert proof, eighteen across the feature. The complete suite now has 622 tests and both isolated release commands must rerun; earlier 621-test evidence is retained at its exact source head. No statistical, recipe, learner or dataset change was made." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project @@ -76,7 +80,7 @@ files[24]{path,scope}: test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[8]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[9]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop @@ -85,6 +89,7 @@ tests[8]{command,scope,timeout_seconds,provenance{author,created_at,source_kind, "node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T09:52:27.463Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity|one pre-approved\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T10:31:09.686Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"ambiguous outer meta|shared inner promotion|promotion headroom counts|inner promotion-budget\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T12:15:16.768Z",local_mutation,feat/meta-recursive-recipe-loop + node --test test/meta.test.ts,project,600,codex-agent,"2026-10-18T12:46:31.272Z",local_mutation,feat/meta-recursive-recipe-loop docs[7]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 9f79fd21..a67d66f2 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -73,3 +73,7 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T12:17:47.381Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/38","value":{"created_at":"2026-10-18T12:17:47.381Z","author":"codex-agent","text":"Restored PM-linked review command passes 4/4, zero failures/cancellations/skips, using the repository-pinned CLI with explicit author. The outside-consumption regression includes another loop sharing the reservation prefix but outside its canonical inner namespace, so a broad prefix cannot hide consumed promotions. The full meta suite passed 22/22 and the focused linked run also covers the final pre-publication audit target. Result persistence remains disabled by project policy, so this comment records the receipt. Previous complete release CI on 39e6c5e passed 617/617 in all three variants; the new source has 621 tests and will be checked by both complete commands with isolated HOME/Git identity. No new passing full-gate result is claimed yet. Live and sanity receipts, the promotion criterion, dependency pins and releases remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:17:47.381Z"}],"before_hash":"9f2789e259162dbcf07eeb073bf3cc0d52adb8b323295bc5c0b72972435ce760","after_hash":"9cd5abe82a012ac67822e6350c81ba6e1221d4a7dfb4077015203c74d0a268c7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e902c9bd41afbbde09b3751af655021eba6cba47d2f1ce92247b72743573677b"} {"hash_algorithm":"sha256","ts":"2026-10-18T12:36:35.608Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/39","value":{"created_at":"2026-10-18T12:36:35.608Z","author":"codex-agent","text":"Source-verification CI run 39126701196 on 268d04a9fdd22960a78d9d675a6c342f29153c74 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 621/621, zero failures/cancellations/skips, 100/100/100/100 statements/lines/branches/functions across all 35 declared sources and 295 documented declarations. Identity, publish attestation, production audit, packaging and changelog checks pass; CodeQL passes. Full meta suite 22/22 and PM-linked review regressions 4/4 pass. Four independent new behavioral reverts fail 0/1 each and fixed sources are restored, bringing the total to seventeen. CodeRabbit inspected both fixes at this source head, explicitly did not execute tests, and resolved both threads itself. No author resolution request was made. Zero open GitHub issue findings. Fresh no-local clone strict health passes with installed merge drivers and isolated Git identity; existing advisory warnings remain and tracker history is append-only. Main is unchanged, source worktree is clean, live/sanity receipts and thresholds are unchanged, and releases remain disabled. The final documentation/claim-release commit will receive an exact-head matrix rerun before handoff; no merge or close is performed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:36:35.608Z"}],"before_hash":"9cd5abe82a012ac67822e6350c81ba6e1221d4a7dfb4077015203c74d0a268c7","after_hash":"d56fbf4ab6250ea56f8e6b1636b88fd47a6039f0c1ff1ef718c477046c6194dd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"61893124d6a02d3cc264e793debfffca1d1cea0221c7e15a06cc6141b2b66d14"} {"hash_algorithm":"sha256","ts":"2026-10-18T12:36:36.367Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:36:36.367Z"}],"before_hash":"d56fbf4ab6250ea56f8e6b1636b88fd47a6039f0c1ff1ef718c477046c6194dd","after_hash":"9667a3b132030975cb7b7b03bae9f51caf3c9bebbfc58a009a5e1149a38f9215","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"ae2fdd4c6218c6682889c8c632c6ee111fecaef8006c327a8870b8226f2837d3"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:42:17.878Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:42:17.878Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"9667a3b132030975cb7b7b03bae9f51caf3c9bebbfc58a009a5e1149a38f9215","after_hash":"1c32bb07b771a086c62d7e54d47faa5a8f53c67d35a7a8c6e94d6138e067cf78","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"1ed0a785ea2d2f20ce50e34743489edf98659775e3c0fb00525397d479d53442"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:42:18.761Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/40","value":{"created_at":"2026-10-18T12:42:18.761Z","author":"codex-agent","text":"Final self-check identified a resume edge in the new headroom contract: a completed outer programme receipt skips reserveMeta, so a pending inner phase can run after the retained reservation loses promotion_headroom. Adding a real tracker regression that interrupts after programme completion, removes or damages retained capacity, and requires refusal before any process job. Retained capacity must be revalidated inside the owner-fenced execution of every unfinished phase; cached completed reports remain read-only. The preceding 621-test source verification remains valid for its exact head, but handoff waits for this additional regression and full gates."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:42:18.761Z"}],"before_hash":"1c32bb07b771a086c62d7e54d47faa5a8f53c67d35a7a8c6e94d6138e067cf78","after_hash":"bf4f004f52d6288cf3f17f732e7b772ef4c3532bf11211a0fdff989d8751fadd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0f0fdc6e33f3cf99fc856d8be8845ca89a5e3cd44227023549d3f7ca22fd2fa1"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:46:31.306Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/8","value":{"command":"node --test test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T12:46:31.272Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:46:31.306Z"}],"before_hash":"bf4f004f52d6288cf3f17f732e7b772ef4c3532bf11211a0fdff989d8751fadd","after_hash":"74e21d0d76475d0cd84754709975bb3cbbe2f9d29e7ef95fabdb5351ad1e3299","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"6261d0fa4e0c8395536571ba37b81fd78e39dd6ed178ec3a1412c5fc14f41fcd"} +{"hash_algorithm":"sha256","ts":"2026-10-18T12:50:23.568Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/41","value":{"created_at":"2026-10-18T12:50:23.567Z","author":"codex-agent","text":"Retained-capacity regression reproduced the completed-programme replay gap on f491e19: 0/1 with Missing expected rejection. The fix verifies the exact retained allocation inside the owner-fenced execution callback for every unfinished phase; missing records are refused rather than recreated, and cached completed reports remain read-only. The test removes promotion_headroom, understates it, and removes the real reservation file; every case refuses before a process job. Restoring valid evidence resumes and replays without another charge or launch. Removing only the new guarded verification fails 0/1 with the test retained; restoring it passes 1/1. Exact command: node --test --test-name-pattern=\"unfinished meta phases revalidate\" test/meta.test.ts. Full node --test test/meta.test.ts now passes 23/23 through pm test --run --progress, zero failures/cancellations/skips. Build, test typecheck, lint, duplicates and docstrings pass at 35 sources and 295 declarations. This is the fifth new review-round revert proof, eighteen across the feature. The complete suite now has 622 tests and both isolated release commands must rerun; earlier 621-test evidence is retained at its exact source head. No statistical, recipe, learner or dataset change was made."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:50:23.568Z"}],"before_hash":"74e21d0d76475d0cd84754709975bb3cbbe2f9d29e7ef95fabdb5351ad1e3299","after_hash":"ec259f92c22a746102c0d4972ac10ed474e0f8acb57d24fbb62d2a73f0e4013e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0692f508a80b5e1eee5160af9ef6f326fecdecd150738e2d3ba104a200d0400a"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 28c1eebf..b63a29ee 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -86,18 +86,21 @@ Adapters report structured progress and completion evidence over a documented st 0.95-confidence, ten-sample, 0.01-effect gate: gain 0.0686, lower bound 0.036740389785077876, and final-test 5093/10000 to 5806/10000. This is a sanity result, not real-tracker improvement. No gate or real feature was weakened. - [Complete release verification](https://github.com/unbraind/pm-rl/pull/84/checks) + [Preceding complete release verification](https://github.com/unbraind/pm-rl/actions/runs/39126701196) passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: 621/621 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared - budget, conditional promotion and resource-refusal regressions pass; seventeen + budget, conditional promotion and resource-refusal regressions pass; eighteen behaviour-only reverts fail with tests retained and restored code passes. The review round fixes canonical receipt identity, bounded programme ids and README command syntax; the physical OOM test waits for real daemon evidence before its failed supervisor exits. Limits and promotion thresholds are unchanged. The next review adds supported audited outer-lease recovery and atomic inner promotion headroom. Budget exhaustion cannot become recipe evidence; the - complete meta suite passes 22/22 and four new behavioral reverts fail. + complete meta suite passes 23/23 and five new behavioral reverts fail. + An additional regression verifies retained capacity before unfinished phases + execute, even after a completed programme receipt; missing or damaged evidence + refuses without launching a fit or silently reserving capacity again. ## Data boundary and capacity diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 6be23212..2bedd3ab 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -69,8 +69,10 @@ cannot reserve the same headroom. A budget refusal from an inner promotion is an accounting failure and never becomes recipe evidence, even if an earlier inner generation promoted. Other intentional promotion refusals are unchanged. These conservative reservations remain held after failure or cancellation. -Legacy reservations without promotion headroom fail closed; search cannot -reclaim or silently replace them. +Unfinished phases verify the exact retained reservation inside their owner fence, +even when the programme receipt is already complete. Missing or damaged capacity +refuses before training and is never silently recreated. New work refuses legacy +reservations without promotion headroom; cached completed reports remain read-only. Each inner fit also uses the existing atomic process resource reservation, measured completion receipt and settlement. Search cannot spend above either allowance. The packaged process trainer is the only selectable meta trainer. @@ -229,7 +231,7 @@ remain. Guard-only reverts for recipe lineage, public visibility, programme ids, retained reservation case folding and both resource fault injectors fail; restored implementations pass. PM-linked data/recipe, crash/promotion/budget, identity and resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. The expanded -review command passes 7/7. Seventeen independent behavioral reverts fail across +review command passes 7/7. Eighteen independent behavioral reverts fail across the feature and subsequent review rounds; restoring the implementations passes. A separate local full-suite attempt hit the unchanged 300-second HTTP crash-drill @@ -269,3 +271,11 @@ complete meta suite passes 22/22. The source-verification matrix above passes inspected both fixes at `268d04a` and resolved its own threads without executing the tests. No author resolution request was made. The final documentation and claim-release commit receives a separate exact-head CI verification. + +A further resume regression interrupts after the programme receipt completes, +removes or damages retained capacity, and requires refusal before any fit starts. +Restoring the valid reservation resumes without charging it again. Removing only +the fenced retained-capacity check fails that regression; restoring it passes. +The restored full meta suite passes 23/23 through the pinned PM test runner. +This additional source change requires the complete 622-test matrix; the preceding +621-test verification remains evidence for its named source head. diff --git a/meta.ts b/meta.ts index 0aee91d8..56673429 100644 --- a/meta.ts +++ b/meta.ts @@ -116,27 +116,32 @@ async function readMetaReceipt(client: PmClient, key: string) { } } -/** Atomically hold worst-case search allowances once; interrupted programmes retain their reservation. */ -async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, request: MetaRequest, binding: string): Promise { +/** Atomically hold worst-case allowances once, or verify retained capacity before an unfinished phase executes. */ +async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, request: MetaRequest, binding: string, retained = false): Promise { const { config } = request; const charge = { training_samples: (1 + config.meta_generations * config.candidates) * RECIPE_BOUNDS.steps[1] * RECIPE_BOUNDS.batch[1], proposal_calls: request.proposer === "decision-model" ? 2 * config.meta_generations : 0, recipe_promotions: config.meta_generations }; const promotionHeadroom = (1 + config.meta_generations * config.candidates) * RECIPE_BOUNDS.steps[1]; const key = `${request.id}-reservation`; - await commitProcessTransaction({ ...coordinates, transactionId: `${key}-reserve`, steps: [{ id: "reserve", - async inspect() { - const previous = await readMetaReceipt(client, key); - if (previous === null) return { state: "pending" }; - assert.equal(previous.item.type, "Decision", "meta_reservation_drift"); - const record = JSON.parse(String(previous.item.body)) as { format: string; id: string; binding: string; approval: string; charge: JsonValue; promotion_headroom: number }; - assert.equal(record.binding, binding, "meta_reservation_drift"); - assert.equal(record.format, "pm-rl/meta-reservation/1", "meta_reservation_drift"); - assert.equal(record.id, key, "meta_reservation_drift"); - assert.equal(record.approval, (await metaApproval(client, request.approval)).id, "meta_reservation_drift"); - assert.equal(hashJson(record.charge), hashJson(charge), "meta_reservation_drift"); - assert.equal(record.promotion_headroom, promotionHeadroom, "meta_reservation_drift"); - return { state: "applied" }; - }, + /** Read and verify an existing allocation even when the programme or SDK transaction receipt is already complete. */ + const inspect = async (): Promise<{ state: "pending" | "applied" }> => { + const previous = await readMetaReceipt(client, key); + if (previous === null) return { state: "pending" }; + assert.equal(previous.item.type, "Decision", "meta_reservation_drift"); + const record = JSON.parse(String(previous.item.body)) as { format: string; id: string; binding: string; approval: string; charge: JsonValue; promotion_headroom: number }; + assert.equal(record.binding, binding, "meta_reservation_drift"); + assert.equal(record.format, "pm-rl/meta-reservation/1", "meta_reservation_drift"); + assert.equal(record.id, key, "meta_reservation_drift"); + assert.equal(record.approval, (await metaApproval(client, request.approval)).id, "meta_reservation_drift"); + assert.equal(hashJson(record.charge), hashJson(charge), "meta_reservation_drift"); + assert.equal(record.promotion_headroom, promotionHeadroom, "meta_reservation_drift"); + return { state: "applied" }; + }; + if (retained) { + assert.equal((await inspect()).state, "applied", "meta_reservation_missing"); + return; + } + await commitProcessTransaction({ ...coordinates, transactionId: `${key}-reserve`, steps: [{ id: "reserve", inspect, async apply() { const approval = await metaApproval(client, request.approval); const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); @@ -264,7 +269,10 @@ export async function runRlMeta(client: PmClient, coordinates: ProcessCoordinate /** Verify approval identity at every boundary, and notify observers only after the receipt is durable. */ const step: RlDurableStep = async (key, value, execute) => { assert.equal((await metaApproval(client, request.approval)).digest, approval.digest, "meta_budget_drift"); - const result = await durable(key, { binding, value }, execute); + const result = await durable(key, { binding, value }, async () => { + if (key !== "programme") await reserveMeta(client, coordinates, request, binding, true); + return execute(); + }); await request.onStep?.(key); return result; }; diff --git a/test/meta.test.ts b/test/meta.test.ts index ebf9122d..22d3dab5 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -99,11 +99,34 @@ test("shared inner promotion headroom refuses before training and reserves atomi await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, id, config), onStep() { throw new Error("same headroom adopted"); } }), /same headroom adopted/); assert.equal(String((await w.client.get(reservation.id)).item.body), body); for (const promotion_headroom of [undefined, -1, 0.5, Number.MAX_SAFE_INTEGER + 1]) { - await w.client.update(reservation.id, { body: JSON.stringify({ ...JSON.parse(body), promotion_headroom }) }); + await w.client.update(reservation.id, { body: JSON.stringify({ ...JSON.parse(body) as Record, promotion_headroom }) }); await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "bad-capacity", config)), /meta_promotion_reservation_charge/); } }); +test("unfinished meta phases revalidate retained headroom after a completed programme receipt", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const request = requestFor(w, "retained-capacity", { ...metaConfig, meta_generations: 1, candidates: 1 }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, onStep(key) { if (key === "programme") throw new Error("programme complete"); } }), /programme complete/); + const reservation = await w.client.get("retained-capacity-reservation"); const original = String(reservation.item.body); + for (const promotion_headroom of [undefined, 0]) { + await w.client.update(reservation.item.id, { body: JSON.stringify({ ...JSON.parse(original) as Record, promotion_headroom }) }); + await assert.rejects(runRlMeta(w.client, w.coordinates, request), /meta_reservation_drift/); + assert.equal((await listProcessJobs(w.client)).length, 0, "invalid retained capacity must refuse before a fit launches"); + } + await w.client.update(reservation.item.id, { body: original }); + const path = join(w.coordinates.pmRoot, "decisions", `${reservation.item.id}.toon`); + renameSync(path, `${path}.missing`); + try { + await assert.rejects(runRlMeta(w.client, w.coordinates, request), /meta_reservation_missing/); + assert.equal((await listProcessJobs(w.client)).length, 0); + } finally { renameSync(`${path}.missing`, path); } + const report = await runRlMeta(w.client, w.coordinates, request); const jobs = await listProcessJobs(w.client); + assert.equal(report.generations.length, 1); + assert.equal(String((await w.client.get(reservation.item.id)).item.body), original, "restored capacity is adopted, never recharged"); + assert.deepEqual(await runRlMeta(w.client, w.coordinates, request), report); + assert.deepEqual(await listProcessJobs(w.client), jobs); +}); + test("promotion headroom counts outside usage without charging reserved promotions twice", { timeout: 600_000 }, async () => { const w = await metaWorkspace(); const config = { ...metaConfig, meta_generations: 1, candidates: 1 }; const raw = JSON.parse(readFileSync(new URL("../examples/loop-bandit.json", import.meta.url), "utf8")) as Record; @@ -122,9 +145,9 @@ test("promotion headroom counts outside usage without charging reserved promotio await assert.rejects(runRlMeta(w.client, w.coordinates, { ...requestFor(w, "second-capacity", config), onStep: stop }), /capacity reserved/); await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "third-capacity", config)), /meta_promotion_budget_exhausted/); const second = await w.client.get("second-capacity-reservation"); - await w.client.update(second.item.id, { body: JSON.stringify({ ...JSON.parse(String(second.item.body)), promotion_headroom: 0 }) }); + await w.client.update(second.item.id, { body: JSON.stringify({ ...JSON.parse(String(second.item.body)) as Record, promotion_headroom: 0 }) }); const first = await w.client.get("first-capacity-reservation"); - await w.client.update(first.item.id, { body: JSON.stringify({ ...JSON.parse(String(first.item.body)), promotion_headroom: 0 }) }); + await w.client.update(first.item.id, { body: JSON.stringify({ ...JSON.parse(String(first.item.body)) as Record, promotion_headroom: 0 }) }); await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "overdrawn", config)), /meta_promotion_reservation_exceeded/); }); From 579adc7dcd98d41d0ff95f487b584c605cf85066 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 15:10:23 +0200 Subject: [PATCH 17/24] docs: record complete retained-capacity verification --- .agents/pm/features/pm-rl-meta.toon | 7 +++---- .agents/pm/history/pm-rl-meta.jsonl | 2 ++ RECURSIVE_TRAINING.md | 4 ++-- docs/meta-recursive.md | 16 +++++++++------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 3060af99..5cfb6e08 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T12:50:23.568Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T13:10:04.589Z" author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[42]{created_at,author,text}: +comments[43]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -55,6 +53,7 @@ comments[42]{created_at,author,text}: "2026-10-18T12:36:35.608Z",codex-agent,"Source-verification CI run 39126701196 on 268d04a9fdd22960a78d9d675a6c342f29153c74 passes all three complete isolated-identity gates: npm run release:check on Node 22 and 26, and bun run release:check on Node 26. Each reports 621/621, zero failures/cancellations/skips, 100/100/100/100 statements/lines/branches/functions across all 35 declared sources and 295 documented declarations. Identity, publish attestation, production audit, packaging and changelog checks pass; CodeQL passes. Full meta suite 22/22 and PM-linked review regressions 4/4 pass. Four independent new behavioral reverts fail 0/1 each and fixed sources are restored, bringing the total to seventeen. CodeRabbit inspected both fixes at this source head, explicitly did not execute tests, and resolved both threads itself. No author resolution request was made. Zero open GitHub issue findings. Fresh no-local clone strict health passes with installed merge drivers and isolated Git identity; existing advisory warnings remain and tracker history is append-only. Main is unchanged, source worktree is clean, live/sanity receipts and thresholds are unchanged, and releases remain disabled. The final documentation/claim-release commit will receive an exact-head matrix rerun before handoff; no merge or close is performed." "2026-10-18T12:42:18.761Z",codex-agent,"Final self-check identified a resume edge in the new headroom contract: a completed outer programme receipt skips reserveMeta, so a pending inner phase can run after the retained reservation loses promotion_headroom. Adding a real tracker regression that interrupts after programme completion, removes or damages retained capacity, and requires refusal before any process job. Retained capacity must be revalidated inside the owner-fenced execution of every unfinished phase; cached completed reports remain read-only. The preceding 621-test source verification remains valid for its exact head, but handoff waits for this additional regression and full gates." "2026-10-18T12:50:23.567Z",codex-agent,"Retained-capacity regression reproduced the completed-programme replay gap on f491e19: 0/1 with Missing expected rejection. The fix verifies the exact retained allocation inside the owner-fenced execution callback for every unfinished phase; missing records are refused rather than recreated, and cached completed reports remain read-only. The test removes promotion_headroom, understates it, and removes the real reservation file; every case refuses before a process job. Restoring valid evidence resumes and replays without another charge or launch. Removing only the new guarded verification fails 0/1 with the test retained; restoring it passes 1/1. Exact command: node --test --test-name-pattern=\"unfinished meta phases revalidate\" test/meta.test.ts. Full node --test test/meta.test.ts now passes 23/23 through pm test --run --progress, zero failures/cancellations/skips. Build, test typecheck, lint, duplicates and docstrings pass at 35 sources and 295 declarations. This is the fifth new review-round revert proof, eighteen across the feature. The complete suite now has 622 tests and both isolated release commands must rerun; earlier 621-test evidence is retained at its exact source head. No statistical, recipe, learner or dataset change was made." + "2026-10-18T13:09:57.963Z",codex-agent,"Complete source verification on d2de7dc0a4a2cbb7f4ffef33734e5f3d39e5cde6, CI run 39128976135, passes npm run release:check on Node 22 and 26 and bun run release:check on Node 26, each with 622/622, zero failures/cancellations/skips, all four coverage metrics 100%, all 35 sources and 295 documented declarations. Every required identity, publish-attestation, audit, packaging and changelog check passes; CodeQL passes. Full meta suite passes 23/23 through the pinned PM runner. Five new independent behavioral reverts fail 0/1 each: force forwarding, recovery guidance, the old reservation function, promotion-budget refusal handling, and retained-capacity validation after a completed programme receipt. All fixed code is restored, eighteen proofs total. Fresh no-local clone strict health passes with merge drivers and isolated Git identity, retaining the two existing advisories. Both review threads were replied to after push and resolved by CodeRabbit itself after static inspection; no author resolution request was made, and no independent final-head approval is claimed. Main is unchanged; live and sanity receipts, statistical thresholds and dependency pins are unchanged. Releasing the claim for handoff while keeping the item in progress. The documentation-only final commit will receive a complete exact-head matrix rerun before the final report; no merge, close or publication is performed." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index a67d66f2..ff734720 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -77,3 +77,5 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T12:42:18.761Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/40","value":{"created_at":"2026-10-18T12:42:18.761Z","author":"codex-agent","text":"Final self-check identified a resume edge in the new headroom contract: a completed outer programme receipt skips reserveMeta, so a pending inner phase can run after the retained reservation loses promotion_headroom. Adding a real tracker regression that interrupts after programme completion, removes or damages retained capacity, and requires refusal before any process job. Retained capacity must be revalidated inside the owner-fenced execution of every unfinished phase; cached completed reports remain read-only. The preceding 621-test source verification remains valid for its exact head, but handoff waits for this additional regression and full gates."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:42:18.761Z"}],"before_hash":"1c32bb07b771a086c62d7e54d47faa5a8f53c67d35a7a8c6e94d6138e067cf78","after_hash":"bf4f004f52d6288cf3f17f732e7b772ef4c3532bf11211a0fdff989d8751fadd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0f0fdc6e33f3cf99fc856d8be8845ca89a5e3cd44227023549d3f7ca22fd2fa1"} {"hash_algorithm":"sha256","ts":"2026-10-18T12:46:31.306Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/8","value":{"command":"node --test test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T12:46:31.272Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:46:31.306Z"}],"before_hash":"bf4f004f52d6288cf3f17f732e7b772ef4c3532bf11211a0fdff989d8751fadd","after_hash":"74e21d0d76475d0cd84754709975bb3cbbe2f9d29e7ef95fabdb5351ad1e3299","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"6261d0fa4e0c8395536571ba37b81fd78e39dd6ed178ec3a1412c5fc14f41fcd"} {"hash_algorithm":"sha256","ts":"2026-10-18T12:50:23.568Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/41","value":{"created_at":"2026-10-18T12:50:23.567Z","author":"codex-agent","text":"Retained-capacity regression reproduced the completed-programme replay gap on f491e19: 0/1 with Missing expected rejection. The fix verifies the exact retained allocation inside the owner-fenced execution callback for every unfinished phase; missing records are refused rather than recreated, and cached completed reports remain read-only. The test removes promotion_headroom, understates it, and removes the real reservation file; every case refuses before a process job. Restoring valid evidence resumes and replays without another charge or launch. Removing only the new guarded verification fails 0/1 with the test retained; restoring it passes 1/1. Exact command: node --test --test-name-pattern=\"unfinished meta phases revalidate\" test/meta.test.ts. Full node --test test/meta.test.ts now passes 23/23 through pm test --run --progress, zero failures/cancellations/skips. Build, test typecheck, lint, duplicates and docstrings pass at 35 sources and 295 declarations. This is the fifth new review-round revert proof, eighteen across the feature. The complete suite now has 622 tests and both isolated release commands must rerun; earlier 621-test evidence is retained at its exact source head. No statistical, recipe, learner or dataset change was made."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:50:23.568Z"}],"before_hash":"74e21d0d76475d0cd84754709975bb3cbbe2f9d29e7ef95fabdb5351ad1e3299","after_hash":"ec259f92c22a746102c0d4972ac10ed474e0f8acb57d24fbb62d2a73f0e4013e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0692f508a80b5e1eee5160af9ef6f326fecdecd150738e2d3ba104a200d0400a"} +{"hash_algorithm":"sha256","ts":"2026-10-18T13:09:57.963Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/42","value":{"created_at":"2026-10-18T13:09:57.963Z","author":"codex-agent","text":"Complete source verification on d2de7dc0a4a2cbb7f4ffef33734e5f3d39e5cde6, CI run 39128976135, passes npm run release:check on Node 22 and 26 and bun run release:check on Node 26, each with 622/622, zero failures/cancellations/skips, all four coverage metrics 100%, all 35 sources and 295 documented declarations. Every required identity, publish-attestation, audit, packaging and changelog check passes; CodeQL passes. Full meta suite passes 23/23 through the pinned PM runner. Five new independent behavioral reverts fail 0/1 each: force forwarding, recovery guidance, the old reservation function, promotion-budget refusal handling, and retained-capacity validation after a completed programme receipt. All fixed code is restored, eighteen proofs total. Fresh no-local clone strict health passes with merge drivers and isolated Git identity, retaining the two existing advisories. Both review threads were replied to after push and resolved by CodeRabbit itself after static inspection; no author resolution request was made, and no independent final-head approval is claimed. Main is unchanged; live and sanity receipts, statistical thresholds and dependency pins are unchanged. Releasing the claim for handoff while keeping the item in progress. The documentation-only final commit will receive a complete exact-head matrix rerun before the final report; no merge, close or publication is performed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:09:57.963Z"}],"before_hash":"ec259f92c22a746102c0d4972ac10ed474e0f8acb57d24fbb62d2a73f0e4013e","after_hash":"d5f10f3e8b9a7ddd96edad68f16ff8ee2b664ea5c91aaa8564699b1a667e3d9e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"bef13bb1409576472f141b7d08ddb74f7358873144bce03e7ebd811c381b592c"} +{"hash_algorithm":"sha256","ts":"2026-10-18T13:10:04.589Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:10:04.589Z"}],"before_hash":"d5f10f3e8b9a7ddd96edad68f16ff8ee2b664ea5c91aaa8564699b1a667e3d9e","after_hash":"fd89f4bc3cb94d7ebc4774db7d771cf30402490f047fbdb5daeeba3ca1dba8e4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"bd698630b73219dae24caefd74a436f2d54524b2cc91686e912aeddcc9b47a42"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index b63a29ee..cf544c1f 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -86,9 +86,9 @@ Adapters report structured progress and completion evidence over a documented st 0.95-confidence, ten-sample, 0.01-effect gate: gain 0.0686, lower bound 0.036740389785077876, and final-test 5093/10000 to 5806/10000. This is a sanity result, not real-tracker improvement. No gate or real feature was weakened. - [Preceding complete release verification](https://github.com/unbraind/pm-rl/actions/runs/39126701196) + [Complete source verification](https://github.com/unbraind/pm-rl/actions/runs/39128976135) passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: - 621/621 each, zero failures/skips, all four coverage metrics 100% across all + 622/622 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared budget, conditional promotion and resource-refusal regressions pass; eighteen behaviour-only reverts fail with tests retained and restored code passes. diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 2bedd3ab..15249e67 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -209,11 +209,11 @@ predictions, and full disagreement. ## Release verification -The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39126701196) -on `268d04a9fdd22960a78d9d675a6c342f29153c74` +The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39128976135) +on `d2de7dc0a4a2cbb7f4ffef33734e5f3d39e5cde6` executes `npm run release:check` on Node 22 and 26 and `bun run release:check` on Node 26 with isolated HOME and global/system Git configuration. Each passes -621/621 tests, zero failures/skips, 100% statements/lines/branches/functions over +622/622 tests, zero failures/skips, 100% statements/lines/branches/functions over all 35 declared sources, 295 documented declarations, and zero duplicate clones or production audit findings. Thresholds, dependency pins and release approval are unchanged. The live evidence names the measured production source commit; @@ -266,8 +266,7 @@ separate inner-promotion headroom, as specified above. Four new behavioral reverts fail independently: dropping force forwarding, restoring loop-resume guidance, restoring the old reservation function, and removing the specific promotion-budget refusal check. Restored linked regressions pass 4/4 and the -complete meta suite passes 22/22. The source-verification matrix above passes -621/621 in all three variants with all four coverage metrics at 100%. CodeRabbit +initial complete meta suite passed 22/22. CodeRabbit inspected both fixes at `268d04a` and resolved its own threads without executing the tests. No author resolution request was made. The final documentation and claim-release commit receives a separate exact-head CI verification. @@ -277,5 +276,8 @@ removes or damages retained capacity, and requires refusal before any fit starts Restoring the valid reservation resumes without charging it again. Removing only the fenced retained-capacity check fails that regression; restoring it passes. The restored full meta suite passes 23/23 through the pinned PM test runner. -This additional source change requires the complete 622-test matrix; the preceding -621-test verification remains evidence for its named source head. +The source-verification matrix above includes this hardening and passes 622/622 +in every variant with all four coverage metrics at 100%, 35 sources and 295 +documented declarations. Earlier 621-test receipts remain in PM history at their +exact source heads. The documentation-only handoff commit receives its own +complete CI verification; no final-head independent review approval is claimed. From eab900b02d1652884bdde10f12499340005cd4ed Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 15:52:55 +0200 Subject: [PATCH 18/24] fix: preserve meta promotion capacity and refuse invalid evidence --- .agents/pm/features/pm-rl-meta.toon | 12 ++++-- .agents/pm/history/pm-rl-meta.jsonl | 5 +++ RECURSIVE_TRAINING.md | 6 +++ dataset.ts | 2 +- docs/meta-recursive.md | 16 ++++++++ index.ts | 10 +++-- meta.ts | 57 ++++++++++++++++++---------- package.json | 1 + test/dataset.test.ts | 13 +++++++ test/meta.test.ts | 58 ++++++++++++++++++++++++++++- tracker-environment.ts | 6 ++- 11 files changed, 156 insertions(+), 30 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 5cfb6e08..3a81d83d 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,11 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T13:10:04.589Z" +updated_at: "2026-10-18T13:52:41.064Z" +assignee: codex-agent +claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[43]{created_at,author,text}: +comments[46]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -54,6 +56,9 @@ comments[43]{created_at,author,text}: "2026-10-18T12:42:18.761Z",codex-agent,"Final self-check identified a resume edge in the new headroom contract: a completed outer programme receipt skips reserveMeta, so a pending inner phase can run after the retained reservation loses promotion_headroom. Adding a real tracker regression that interrupts after programme completion, removes or damages retained capacity, and requires refusal before any process job. Retained capacity must be revalidated inside the owner-fenced execution of every unfinished phase; cached completed reports remain read-only. The preceding 621-test source verification remains valid for its exact head, but handoff waits for this additional regression and full gates." "2026-10-18T12:50:23.567Z",codex-agent,"Retained-capacity regression reproduced the completed-programme replay gap on f491e19: 0/1 with Missing expected rejection. The fix verifies the exact retained allocation inside the owner-fenced execution callback for every unfinished phase; missing records are refused rather than recreated, and cached completed reports remain read-only. The test removes promotion_headroom, understates it, and removes the real reservation file; every case refuses before a process job. Restoring valid evidence resumes and replays without another charge or launch. Removing only the new guarded verification fails 0/1 with the test retained; restoring it passes 1/1. Exact command: node --test --test-name-pattern=\"unfinished meta phases revalidate\" test/meta.test.ts. Full node --test test/meta.test.ts now passes 23/23 through pm test --run --progress, zero failures/cancellations/skips. Build, test typecheck, lint, duplicates and docstrings pass at 35 sources and 295 declarations. This is the fifth new review-round revert proof, eighteen across the feature. The complete suite now has 622 tests and both isolated release commands must rerun; earlier 621-test evidence is retained at its exact source head. No statistical, recipe, learner or dataset change was made." "2026-10-18T13:09:57.963Z",codex-agent,"Complete source verification on d2de7dc0a4a2cbb7f4ffef33734e5f3d39e5cde6, CI run 39128976135, passes npm run release:check on Node 22 and 26 and bun run release:check on Node 26, each with 622/622, zero failures/cancellations/skips, all four coverage metrics 100%, all 35 sources and 295 documented declarations. Every required identity, publish-attestation, audit, packaging and changelog check passes; CodeQL passes. Full meta suite passes 23/23 through the pinned PM runner. Five new independent behavioral reverts fail 0/1 each: force forwarding, recovery guidance, the old reservation function, promotion-budget refusal handling, and retained-capacity validation after a completed programme receipt. All fixed code is restored, eighteen proofs total. Fresh no-local clone strict health passes with merge drivers and isolated Git identity, retaining the two existing advisories. Both review threads were replied to after push and resolved by CodeRabbit itself after static inspection; no author resolution request was made, and no independent final-head approval is claimed. Main is unchanged; live and sanity receipts, statistical thresholds and dependency pins are unchanged. Releasing the claim for handoff while keeping the item in progress. The documentation-only final commit will receive a complete exact-head matrix rerun before the final report; no merge, close or publication is performed." + "2026-10-18T13:46:53.450Z",codex-agent,"Review round on 579adc7: read all four unresolved threads and newest full review; no open GitHub issues name this PR. Validate case-insensitive repository exclusions, protect retained meta headroom at every promotion, package the linked sanity receipt, and fail closed on unclassified inner refusals. Add focused behavioral revert proofs; preserve frozen live acceptance and thresholds. Registry CLI is 2026.10.18; pinned SDK remains unchanged." + "2026-10-18T13:51:44.304Z",codex-agent,"All four findings verified and fixed: casefold excluded remotes before metadata/history; shared writer-locked promotion accounting preserves unconsumed meta reservations for their owner; package includes the linked sanity receipt; only explicit candidate-contamination promotion refusals may retain policy evidence. Revert proofs with regressions retained: remove casefold -> mixed-case test 0/1; remove promoteGenerationCore retained-capacity check -> ordinary concurrency test 0/1 (two promotions instead of one); remove packaged receipt -> dry-run tarball test 0/1; restore old fitRecipe refusal guard -> operational-refusal test 0/1 (missing rejection). Restored new regressions 4/4. No live rerun or thresholds changed." + "2026-10-18T13:52:41.064Z",codex-agent,"Focused restored regressions pass 4/4 through the pinned PM runner. Typecheck, build, test compilation, lint, zero-duplication gate, docstrings (35 sources / 295 documented declarations), and changelog checks pass. The complete linked meta suite is running; complete npm and Bun release gates will be verified in the isolated CI matrix. A comma-separated bare files argument was correctly refused; repeated --add flags were used instead. Existing file links were retained." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project @@ -79,7 +84,7 @@ files[24]{path,scope}: test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[9]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[10]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop @@ -89,6 +94,7 @@ tests[9]{command,scope,timeout_seconds,provenance{author,created_at,source_kind, "node --test --test-name-pattern=\"canonical reservation|canonical proposal|programme id bounds|README dataset|decision-model proposals|programme identity|one pre-approved\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T10:31:09.686Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"ambiguous outer meta|shared inner promotion|promotion headroom counts|inner promotion-budget\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T12:15:16.768Z",local_mutation,feat/meta-recursive-recipe-loop node --test test/meta.test.ts,project,600,codex-agent,"2026-10-18T12:46:31.272Z",local_mutation,feat/meta-recursive-recipe-loop + "node --test --test-name-pattern=\"mixed-case excluded|ordinary concurrent|operational and unclassified|published meta\" test/dataset.test.ts test/meta.test.ts",project,600,codex-agent,"2026-10-18T13:51:45.650Z",local_mutation,feat/meta-recursive-recipe-loop docs[7]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index ff734720..102152b3 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -79,3 +79,8 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T12:50:23.568Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/41","value":{"created_at":"2026-10-18T12:50:23.567Z","author":"codex-agent","text":"Retained-capacity regression reproduced the completed-programme replay gap on f491e19: 0/1 with Missing expected rejection. The fix verifies the exact retained allocation inside the owner-fenced execution callback for every unfinished phase; missing records are refused rather than recreated, and cached completed reports remain read-only. The test removes promotion_headroom, understates it, and removes the real reservation file; every case refuses before a process job. Restoring valid evidence resumes and replays without another charge or launch. Removing only the new guarded verification fails 0/1 with the test retained; restoring it passes 1/1. Exact command: node --test --test-name-pattern=\"unfinished meta phases revalidate\" test/meta.test.ts. Full node --test test/meta.test.ts now passes 23/23 through pm test --run --progress, zero failures/cancellations/skips. Build, test typecheck, lint, duplicates and docstrings pass at 35 sources and 295 declarations. This is the fifth new review-round revert proof, eighteen across the feature. The complete suite now has 622 tests and both isolated release commands must rerun; earlier 621-test evidence is retained at its exact source head. No statistical, recipe, learner or dataset change was made."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T12:50:23.568Z"}],"before_hash":"74e21d0d76475d0cd84754709975bb3cbbe2f9d29e7ef95fabdb5351ad1e3299","after_hash":"ec259f92c22a746102c0d4972ac10ed474e0f8acb57d24fbb62d2a73f0e4013e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0692f508a80b5e1eee5160af9ef6f326fecdecd150738e2d3ba104a200d0400a"} {"hash_algorithm":"sha256","ts":"2026-10-18T13:09:57.963Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/42","value":{"created_at":"2026-10-18T13:09:57.963Z","author":"codex-agent","text":"Complete source verification on d2de7dc0a4a2cbb7f4ffef33734e5f3d39e5cde6, CI run 39128976135, passes npm run release:check on Node 22 and 26 and bun run release:check on Node 26, each with 622/622, zero failures/cancellations/skips, all four coverage metrics 100%, all 35 sources and 295 documented declarations. Every required identity, publish-attestation, audit, packaging and changelog check passes; CodeQL passes. Full meta suite passes 23/23 through the pinned PM runner. Five new independent behavioral reverts fail 0/1 each: force forwarding, recovery guidance, the old reservation function, promotion-budget refusal handling, and retained-capacity validation after a completed programme receipt. All fixed code is restored, eighteen proofs total. Fresh no-local clone strict health passes with merge drivers and isolated Git identity, retaining the two existing advisories. Both review threads were replied to after push and resolved by CodeRabbit itself after static inspection; no author resolution request was made, and no independent final-head approval is claimed. Main is unchanged; live and sanity receipts, statistical thresholds and dependency pins are unchanged. Releasing the claim for handoff while keeping the item in progress. The documentation-only final commit will receive a complete exact-head matrix rerun before the final report; no merge, close or publication is performed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:09:57.963Z"}],"before_hash":"ec259f92c22a746102c0d4972ac10ed474e0f8acb57d24fbb62d2a73f0e4013e","after_hash":"d5f10f3e8b9a7ddd96edad68f16ff8ee2b664ea5c91aaa8564699b1a667e3d9e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"bef13bb1409576472f141b7d08ddb74f7358873144bce03e7ebd811c381b592c"} {"hash_algorithm":"sha256","ts":"2026-10-18T13:10:04.589Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:10:04.589Z"}],"before_hash":"d5f10f3e8b9a7ddd96edad68f16ff8ee2b664ea5c91aaa8564699b1a667e3d9e","after_hash":"fd89f4bc3cb94d7ebc4774db7d771cf30402490f047fbdb5daeeba3ca1dba8e4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"bd698630b73219dae24caefd74a436f2d54524b2cc91686e912aeddcc9b47a42"} +{"hash_algorithm":"sha256","ts":"2026-10-18T13:46:52.010Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:46:52.010Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"fd89f4bc3cb94d7ebc4774db7d771cf30402490f047fbdb5daeeba3ca1dba8e4","after_hash":"fb124d40865fe92c0d7c9829fcec37c5b21c4883b08a34ae31815a6e54234bcd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"ae6d233ec79238edeacefb90d2bfa57da70eb0e8ee6eabd2e11586aa9b0a2961"} +{"hash_algorithm":"sha256","ts":"2026-10-18T13:46:53.450Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/43","value":{"created_at":"2026-10-18T13:46:53.450Z","author":"codex-agent","text":"Review round on 579adc7: read all four unresolved threads and newest full review; no open GitHub issues name this PR. Validate case-insensitive repository exclusions, protect retained meta headroom at every promotion, package the linked sanity receipt, and fail closed on unclassified inner refusals. Add focused behavioral revert proofs; preserve frozen live acceptance and thresholds. Registry CLI is 2026.10.18; pinned SDK remains unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:46:53.450Z"}],"before_hash":"fb124d40865fe92c0d7c9829fcec37c5b21c4883b08a34ae31815a6e54234bcd","after_hash":"4ce11016db7b4ede76650fb6e879dd8e3f41fdcf2f085e4055041b61e1e211e0","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c6ea25977530ca7cfc713b84e76daf6abb8b66976211a6a4a1151ec450304ecf"} +{"hash_algorithm":"sha256","ts":"2026-10-18T13:51:44.304Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/44","value":{"created_at":"2026-10-18T13:51:44.304Z","author":"codex-agent","text":"All four findings verified and fixed: casefold excluded remotes before metadata/history; shared writer-locked promotion accounting preserves unconsumed meta reservations for their owner; package includes the linked sanity receipt; only explicit candidate-contamination promotion refusals may retain policy evidence. Revert proofs with regressions retained: remove casefold -> mixed-case test 0/1; remove promoteGenerationCore retained-capacity check -> ordinary concurrency test 0/1 (two promotions instead of one); remove packaged receipt -> dry-run tarball test 0/1; restore old fitRecipe refusal guard -> operational-refusal test 0/1 (missing rejection). Restored new regressions 4/4. No live rerun or thresholds changed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:51:44.304Z"}],"before_hash":"4ce11016db7b4ede76650fb6e879dd8e3f41fdcf2f085e4055041b61e1e211e0","after_hash":"6427b54eb49212d651dd9581beea3df4307eea71bdb832d640b49db7842889b2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c791c2858b8046e18607ad293abe741ea6de1840478b3cb5b9a27865497aafb9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T13:51:45.683Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/9","value":{"command":"node --test --test-name-pattern=\"mixed-case excluded|ordinary concurrent|operational and unclassified|published meta\" test/dataset.test.ts test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T13:51:45.650Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:51:45.683Z"}],"before_hash":"6427b54eb49212d651dd9581beea3df4307eea71bdb832d640b49db7842889b2","after_hash":"56d987ca892d90ed363474dc8e65c98d86a73232835cc2d9f6cb8249cf115d85","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fe32fa16f61d66edf3d8e01d942f26428e262a393c28d58f2fcbef6a33ddb1c9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T13:52:41.064Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/45","value":{"created_at":"2026-10-18T13:52:41.064Z","author":"codex-agent","text":"Focused restored regressions pass 4/4 through the pinned PM runner. Typecheck, build, test compilation, lint, zero-duplication gate, docstrings (35 sources / 295 documented declarations), and changelog checks pass. The complete linked meta suite is running; complete npm and Bun release gates will be verified in the isolated CI matrix. A comma-separated bare files argument was correctly refused; repeated --add flags were used instead. Existing file links were retained."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:52:41.064Z"}],"before_hash":"56d987ca892d90ed363474dc8e65c98d86a73232835cc2d9f6cb8249cf115d85","after_hash":"94509b90d23e8935bb74bea4403cb3e0987ef6f939b8a07340e0dc3a04a55757","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"750035e33123dc89a3810a6d2e1dbc35ccbf0848fa90ad664d53ecdbeddb31da"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index cf544c1f..35ad3eb0 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -101,6 +101,12 @@ Adapters report structured progress and completion evidence over a documented st An additional regression verifies retained capacity before unfinished phases execute, even after a completed programme receipt; missing or damaged evidence refuses without launching a fit or silently reserving capacity again. + The next review protects unconsumed meta headroom at the shared promotion gate, + including concurrent ordinary loops. Operational or unclassified promotion + refusals cannot become recipe evidence on replay. Mixed-case excluded remotes + refuse before metadata/history reads, and the package ships the linked sanity + receipt. Four additional behavioral reverts fail; restored regressions pass 4/4. + Live receipts and promotion thresholds remain unchanged. ## Data boundary and capacity diff --git a/dataset.ts b/dataset.ts index 934d3117..e2390411 100644 --- a/dataset.ts +++ b/dataset.ts @@ -81,7 +81,7 @@ export function buildTrackerDataset(directories: readonly string[], output: stri const match = /^(?:https:\/\/github\.com\/|git@github\.com:)([\w-]+\/pm-[\w-]+?)(?:\.git)?$/.exec(remote); assert.ok(match !== null, "dataset_github_source"); const repo = match[1]; - assert.ok(!["pm-web", "pm-gpt", "pm-cli"].includes(repo.split("/")[1]), "dataset_excluded_repo"); + assert.ok(!["pm-web", "pm-gpt", "pm-cli"].includes(repo.split("/")[1].toLowerCase()), "dataset_excluded_repo"); const metadata = JSON.parse(sourceCommand("gh", ["repo", "view", repo, "--json", "visibility,licenseInfo,nameWithOwner"], root)) as { visibility: string; licenseInfo: { key: string } | null; nameWithOwner: string }; assert.ok(metadata.visibility === "PUBLIC" && metadata.licenseInfo?.key === "mit" && metadata.nameWithOwner.toLowerCase() === repo.toLowerCase(), "dataset_public_mit_required"); const commit = sourceCommand("git", ["rev-parse", "HEAD"], root); diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 15249e67..c794f28c 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -281,3 +281,19 @@ in every variant with all four coverage metrics at 100%, 35 sources and 295 documented declarations. Earlier 621-test receipts remain in PM history at their exact source heads. The documentation-only handoff commit receives its own complete CI verification; no final-head independent review approval is claimed. + +The full review of `579adc7` closes the remaining shared-approval gap: every +promotion checks unconsumed meta headroom under the same writer lock, including +ordinary loops. Only a canonical owning inner generation can consume its own +reservation; unused capacity remains held conservatively. A concurrent real +tracker regression gives two ordinary loops one free slot beside four reserved +slots, then resumes the owner without another reservation or process charge. +Unclassified inner promotion refusals, including accounting, malformed-spec and +lock failures, refuse recipe evidence on initial execution and replay; the +explicit candidate-contamination refusal still retains the last accepted policy. +Repository exclusions compare names without case sensitivity before metadata or +history reads, and the published package includes both linked evidence receipts. +Four independent behavior-only reverts fail the new regressions; restoring the +fixes passes 4/4. The frozen real-data and known-signal receipts are unchanged. +Complete release-gate verification for this review head is recorded in the PR +and PM item after CI finishes. diff --git a/index.ts b/index.ts index 9cca6b8f..dc96abb9 100644 --- a/index.ts +++ b/index.ts @@ -155,7 +155,7 @@ export { buildTrackerDataset, readTrackerDataset, readTrackerSplit, type Tracker export { runRlMeta, parseMetaConfig, type MetaConfig, type MetaRequest, type MetaReport } from "./meta.ts"; import { buildTrackerDataset } from "./dataset.ts"; -import { runRlMeta, parseMetaConfig, type MetaReport } from "./meta.ts"; +import { runRlMeta, parseMetaConfig, retainedMetaPromotionHeadroom, type MetaReport } from "./meta.ts"; import { trainLmStep, evaluateLmStep, lmTrainingJson, restoreLmTraining, restoreLmGeneration, serializeLmCheckpoint, @@ -2459,10 +2459,12 @@ async function promoteGenerationCore(client: PmClient, coordinates: WorkspaceCoo // is a comparison between two values, and re-reading only one of them // leaves the comparison stale in the other direction. const lockedApprovalSpec = await readApprovalSpec(client, approvalId); - promotedCount = (await promotedGenerationIdsUnderApproval(client, approvalId)).length; + const promotedIds = await promotedGenerationIdsUnderApproval(client, approvalId); + promotedCount = promotedIds.length; + const retainedHeadroom = await retainedMetaPromotionHeadroom(client, approvalId, promotedIds, String(current.item.id)); permittedPromotions = lockedApprovalSpec.permitted_promotions; - if (promotedCount >= permittedPromotions) { - fail(`Advancing past the approved promotion budget is refused. ${promotedCount} promotion(s) consumed; approval ${approvalId} permits ${permittedPromotions}. Extend approval item ${approvalId} to authorize more promotions.`, "budget_exceeded", EXIT_CODE.CONFLICT); + if (promotedCount + retainedHeadroom >= permittedPromotions) { + fail(`Advancing past the approved promotion budget is refused. ${promotedCount} promotion(s) consumed; ${retainedHeadroom} promotion(s) held for meta search; approval ${approvalId} permits ${permittedPromotions}. Extend approval item ${approvalId} to authorize more promotions.`, "budget_exceeded", EXIT_CODE.CONFLICT); } await client.update(id, { // Rendered from the IN-LOCK spec, so a peer edit to a field the diff --git a/meta.ts b/meta.ts index 56673429..d6c0069b 100644 --- a/meta.ts +++ b/meta.ts @@ -116,6 +116,38 @@ async function readMetaReceipt(client: PmClient, key: string) { } } +/** Read canonical reservation records for one approval, ignoring foreign copies and unrelated Decisions. */ +async function metaReservations(client: PmClient, approval: string): Promise> }[]> { + const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); + const reservations: { prefix: string; record: NonNullable> }[] = []; + for (const item of items.items.filter((entry) => entry.type === "Decision" && entry.id.endsWith("-reservation"))) { + const record = metaReservation(String((await readCompleteLoopItem(client, item.id)).item.body)); + if (record === null) continue; + const identity = record.id.toLowerCase(); + if ((item.id === identity || item.id.endsWith(`-${identity}`)) && record.approval === approval) { + reservations.push({ prefix: item.id.slice(0, -"-reservation".length), record }); + } + } + return reservations; +} + +/** Count unconsumed meta capacity under the writer lock, exempting only the candidate's owning reservation. */ +export async function retainedMetaPromotionHeadroom(client: PmClient, approval: string, promoted: readonly string[], candidate?: string): Promise { + let retained = 0; + for (const { prefix, record } of await metaReservations(client, approval)) { + assert.ok(Number.isSafeInteger(record.promotion_headroom) && record.promotion_headroom >= 0, "meta_promotion_reservation_charge"); + /** Only canonical bounded inner generation identities can consume this reservation. */ + const owns = (id: string): boolean => id.startsWith(`${prefix}-`) && /^-(?:initial|m(?:[1-9]|10)-c[0-7])-g[12]$/.test(id.slice(prefix.length)); + const consumed = promoted.filter(owns).length; + assert.ok(consumed <= record.promotion_headroom, "meta_promotion_reservation_exceeded"); + if (candidate !== undefined && owns(candidate)) { + assert.ok(consumed < record.promotion_headroom, "meta_promotion_reservation_exceeded"); + } else retained += record.promotion_headroom - consumed; + } + assert.ok(Number.isSafeInteger(retained), "meta_promotion_reservation_charge"); + return retained; +} + /** Atomically hold worst-case allowances once, or verify retained capacity before an unfinished phase executes. */ async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, request: MetaRequest, binding: string, retained = false): Promise { const { config } = request; @@ -146,33 +178,18 @@ async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, re const approval = await metaApproval(client, request.approval); const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); const charges: Record[] = []; - const promotions: { prefix: string; headroom: number; consumed: number }[] = []; - for (const item of items.items.filter((entry) => entry.type === "Decision" && entry.id.endsWith("-reservation"))) { - const record = metaReservation(String((await readCompleteLoopItem(client, item.id)).item.body)); - if (record === null) continue; - const identity = record.id.toLowerCase(); - if ((item.id === identity || item.id.endsWith(`-${identity}`)) && record.approval === approval.id) { - for (const key of ["training_samples", "proposal_calls", "recipe_promotions"]) { - assert.ok(Number.isSafeInteger(record.charge[key]) && record.charge[key] >= 0, "meta_reservation_charge"); - } - charges.push(record.charge); - assert.ok(Number.isSafeInteger(record.promotion_headroom) && record.promotion_headroom >= 0, "meta_promotion_reservation_charge"); - promotions.push({ prefix: item.id.slice(0, -"-reservation".length), headroom: record.promotion_headroom, consumed: 0 }); + for (const { record } of await metaReservations(client, approval.id)) { + for (const key of ["training_samples", "proposal_calls", "recipe_promotions"]) { + assert.ok(Number.isSafeInteger(record.charge[key]) && record.charge[key] >= 0, "meta_reservation_charge"); } + charges.push(record.charge); } for (const key of ["training_samples", "proposal_calls", "recipe_promotions"] as const) { const total = charges.reduce((sum, entry) => sum + entry[key], charge[key]); assert.ok(Number.isSafeInteger(total) && total <= approval.limits[key], `meta_budget_exhausted: ${key}`); } - let unreserved = 0; const consumed = items.items.some((item) => item.type === "Generation") ? await promotedGenerationIdsUnderApproval(client, approval.id) : []; - for (const id of consumed) { - const reserved = promotions.find(({ prefix }) => id.startsWith(`${prefix}-`) && /^-(?:initial|m(?:[1-9]|10)-c[0-7])-g[12]$/.test(id.slice(prefix.length))); - if (reserved === undefined) unreserved += 1; - else reserved.consumed += 1; - } - for (const reserved of promotions) assert.ok(reserved.consumed <= reserved.headroom, "meta_promotion_reservation_exceeded"); - const totalPromotions = promotions.reduce((sum, reserved) => sum + reserved.headroom, promotionHeadroom + unreserved); + const totalPromotions = consumed.length + await retainedMetaPromotionHeadroom(client, approval.id, consumed) + promotionHeadroom; assert.ok(Number.isSafeInteger(totalPromotions) && totalPromotions <= approval.promotions, "meta_promotion_budget_exhausted"); await client.create({ id: key, type: "Decision", title: "Reserved bounded recipe search", body: JSON.stringify({ format: "pm-rl/meta-reservation/1", id: key, binding, approval: approval.id, charge, promotion_headroom: promotionHeadroom }) }); }, diff --git a/package.json b/package.json index b2808926..43469efa 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "dist/meta.*", "docs/meta-recursive.md", "docs/meta-live-evidence.json", + "docs/meta-sanity-evidence.json", "dist/tracker-environment.*" ], "engines": { diff --git a/test/dataset.test.ts b/test/dataset.test.ts index 97ecf498..3a842bc4 100644 --- a/test/dataset.test.ts +++ b/test/dataset.test.ts @@ -63,6 +63,19 @@ test("builder fails before reading histories from private, unlicensed, hosted or }); }); +test("mixed-case excluded GitHub repository names refuse before metadata or history reads", async () => { + await withTrackerSources(async ({ root, gh, directories }) => { + writeFileSync(gh, `#!${process.execPath}\nthrow new Error('excluded sources must never query GitHub');\n`); + const project = dirname(dirname(directories[0])); + for (const repo of ["pm-WEB", "pm-GpT", "pm-CLI"]) { + for (const remote of [`git@github.com:public-fixture/${repo}.git`, `https://github.com/public-fixture/${repo}.git`]) { + git(project, ["remote", "set-url", "origin", remote]); + assert.throws(() => buildTrackerDataset(directories, join(root, repo)), /dataset_excluded_repo/); + } + } + }); +}); + test("dataset readers refuse content drift, label leakage and forged repository assignments", async () => { await withTrackerSources(async ({ root, directories }) => { const directory = join(root, "dataset"); const manifest = buildTrackerDataset(directories, directory); diff --git a/test/meta.test.ts b/test/meta.test.ts index 22d3dab5..abe7db52 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -2,7 +2,7 @@ import assert from "node:assert/strict"; import { createServer } from "node:http"; import { once } from "node:events"; -import { fork } from "node:child_process"; +import { execFileSync, fork } from "node:child_process"; import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { hostname } from "node:os"; @@ -151,6 +151,26 @@ test("promotion headroom counts outside usage without charging reserved promotio await assert.rejects(runRlMeta(w.client, w.coordinates, requestFor(w, "overdrawn", config)), /meta_promotion_reservation_exceeded/); }); +test("ordinary concurrent promotions preserve retained meta capacity until its owner consumes it", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); + const request = requestFor(w, "capacity", { ...metaConfig, meta_generations: 1, candidates: 1 }); + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: 5 })}\n\`\`\`` }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, onStep(key) { if (key === "programme") throw new Error("reserved before training"); } }), /reserved before training/); + const reservation = String((await w.client.get("capacity-reservation")).item.body); + const raw = JSON.parse(readFileSync(new URL("../examples/loop-bandit.json", import.meta.url), "utf8")) as Record; + const ordinary = await Promise.all(["outside-first", "capacity-other"].map((id) => runRlLoop(w.client, w.coordinates, { id, config: { ...raw, max_generations: 1 }, approval: w.approval }))); + assert.equal(ordinary.reduce((sum, report) => sum + report.promoted, 0), 1, "only the single unreserved slot is available to ordinary loops"); + const refused = ordinary.find((report) => report.promoted === 0)!; + assert.equal(refused.stop_reason, "promotion_refused"); assert.match(refused.refusal_reason!, /approved promotion budget/); assert.match(refused.refusal_reason!, /4 promotion\(s\) held for meta search/); + const report = await runRlMeta(w.client, w.coordinates, request); + assert.equal(report.generations.length, 1, "the owner can still use its retained capacity"); + assert.ok((await promotedGenerationIdsUnderApproval(w.client, w.approval)).length <= 5); + assert.equal(String((await w.client.get("capacity-reservation")).item.body), reservation); + const jobs = await listProcessJobs(w.client); + assert.deepEqual(await runRlMeta(w.client, w.coordinates, request), report); + assert.deepEqual(await listProcessJobs(w.client), jobs); +}); + test("inner promotion-budget refusals never become recipe evidence, including after an accepted generation", { timeout: 600_000 }, async () => { for (const permitted of [0, 1]) { const w = await metaWorkspace(); @@ -171,6 +191,42 @@ test("inner promotion-budget refusals never become recipe evidence, including af } }); +test("operational and unclassified inner refusals never become persisted recipe evidence", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: 0 })}\n\`\`\`` }); + const recipe = metaConfig.initial_recipe; + const environment = openTrackerEnvironment(w.client, w.coordinates, w.dataset, metaConfig, w.approval); + await assert.rejects(environment.fit(recipe, "operation-fit", new AbortController().signal), /meta_inner_promotion_budget/); + const generation = await w.client.get("operation-fit-g1"); + const comments = await w.client.comments(generation.item.id, { outputBudget: "unbounded", outputLimit: "unbounded" }); + assert.ok("comments" in comments); + const index = comments.comments.findIndex((comment) => comment.text.includes("approved promotion budget")); + assert.ok(index >= 0); + const jobs = await listProcessJobs(w.client); + for (const reason of [ + "Promotion refused: generation broken has no JSON specification fence, so the approved budget cannot be established.", + "Promotion refused: generation broken has an unparseable specification, so the approved budget cannot be established.", + "Timed out waiting for the promotion writer lock.", "Malformed generation specification.", "Unknown operational refusal.", + ]) { + await w.client.comments(generation.item.id, { edit: index + 1, add: `Loop operation-fit generation 1 promotion refused: ${reason}` }); + for (let replay = 0; replay < 2; replay += 1) { + await assert.rejects(environment.fit(recipe, "operation-fit", new AbortController().signal), /meta_inner_promotion_budget|meta_inner_promotion_unclassified/); + } + } + assert.deepEqual(await listProcessJobs(w.client), jobs, "refusal replay never charges a second process job"); + await w.client.comments(generation.item.id, { edit: index + 1, add: "Loop operation-fit generation 1 promotion refused: Promotion refused: the evaluation set is reachable from the candidate's training data over provenance edges." }); + assert.equal((await environment.fit(recipe, "operation-fit", new AbortController().signal)).weight, 0); +}); + +test("published meta documentation includes every linked evidence receipt", () => { + const packed = JSON.parse(execFileSync("npm", ["pack", "--dry-run", "--json", "--ignore-scripts"], { cwd: new URL("..", import.meta.url), encoding: "utf8", timeout: 30_000 })) as { files: { path: string }[] }[]; + const files = new Set(packed[0].files.map((file) => file.path)); + const documentation = readFileSync(new URL("../docs/meta-recursive.md", import.meta.url), "utf8"); + for (const receipt of ["meta-live-evidence.json", "meta-sanity-evidence.json"]) { + assert.ok(documentation.includes(receipt)); assert.ok(files.has(`docs/${receipt}`), `published documentation must include ${receipt}`); + } +}); + test("meta programme bounds and search domains cannot tune the statistical gate or trainer command", () => { assert.deepEqual(parseMetaConfig(metaConfig), metaConfig); for (const key of ["seed", "meta_generations", "candidates", "timeout_ms", "evaluation_samples"] as const) { diff --git a/tracker-environment.ts b/tracker-environment.ts index d73a3720..77ea7704 100644 --- a/tracker-environment.ts +++ b/tracker-environment.ts @@ -107,7 +107,11 @@ async function fitRecipe(client: PmClient, coordinates: ProcessCoordinates, requ adapter: config.adapter as unknown as JsonValue, } }); assert.ok(!["process_failed", "process_cancelled", "process_invalidated", "wall_limit_exceeded", "checkpoint_limit_exceeded"].includes(report.stop_reason), "meta_inner_failed"); - assert.ok(!(report.stop_reason === "promotion_refused" && /approved promotion budget/.test(String(report.refusal_reason))), "meta_inner_promotion_budget"); + if (report.stop_reason === "promotion_refused") { + const reason = String(report.refusal_reason); + assert.ok(!/approved promotion budget|approved budget cannot be established/.test(reason), "meta_inner_promotion_budget"); + assert.ok(reason.startsWith("Promotion refused: the evaluation set is reachable from the candidate's training data"), "meta_inner_promotion_unclassified"); + } let weight = 0; const accepted = report.generations.filter((generation) => generation.promoted).at(-1); if (accepted !== undefined) { From 49323f0b24092ce4a34d535fbf64e41e28588e59 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:15:20 +0200 Subject: [PATCH 19/24] fix: canonicalize shared approval accounting across SDK aliases --- .agents/pm/features/pm-rl-meta.toon | 11 +++-- .agents/pm/history/pm-rl-meta.jsonl | 5 +++ RECURSIVE_TRAINING.md | 6 ++- docs/meta-recursive.md | 11 +++++ index.ts | 41 ++++++++++++------- meta.ts | 10 +++-- test/meta.test.ts | 63 ++++++++++++++++++++++++++++- 7 files changed, 125 insertions(+), 22 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 3a81d83d..c686027f 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T13:52:41.064Z" +updated_at: "2026-10-18T14:15:16.820Z" assignee: codex-agent claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[46]{created_at,author,text}: +comments[49]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -59,6 +59,9 @@ comments[46]{created_at,author,text}: "2026-10-18T13:46:53.450Z",codex-agent,"Review round on 579adc7: read all four unresolved threads and newest full review; no open GitHub issues name this PR. Validate case-insensitive repository exclusions, protect retained meta headroom at every promotion, package the linked sanity receipt, and fail closed on unclassified inner refusals. Add focused behavioral revert proofs; preserve frozen live acceptance and thresholds. Registry CLI is 2026.10.18; pinned SDK remains unchanged." "2026-10-18T13:51:44.304Z",codex-agent,"All four findings verified and fixed: casefold excluded remotes before metadata/history; shared writer-locked promotion accounting preserves unconsumed meta reservations for their owner; package includes the linked sanity receipt; only explicit candidate-contamination promotion refusals may retain policy evidence. Revert proofs with regressions retained: remove casefold -> mixed-case test 0/1; remove promoteGenerationCore retained-capacity check -> ordinary concurrency test 0/1 (two promotions instead of one); remove packaged receipt -> dry-run tarball test 0/1; restore old fitRecipe refusal guard -> operational-refusal test 0/1 (missing rejection). Restored new regressions 4/4. No live rerun or thresholds changed." "2026-10-18T13:52:41.064Z",codex-agent,"Focused restored regressions pass 4/4 through the pinned PM runner. Typecheck, build, test compilation, lint, zero-duplication gate, docstrings (35 sources / 295 documented declarations), and changelog checks pass. The complete linked meta suite is running; complete npm and Bun release gates will be verified in the isolated CI matrix. A comma-separated bare files argument was correctly refused; repeated --add flags were used instead. Existing file links were retained." + "2026-10-18T13:59:51.977Z",codex-agent,"Pushed eab900b02d1652884bdde10f12499340005cd4ed and replied to all four threads after push. CodeRabbit independently inspected each fix and resolved its own four threads, explicitly without rerunning tests or verifying pending CI. Complete linked meta suite passes 26/26 in 122216 ms with no failures/skips. Fresh no-local clone strict health with merge drivers passes; three existing telemetry/staleness/provenance advisories remain. All main-branch history prefixes and public-path privacy checks pass. Frozen live and sanity receipts are unchanged. Complete isolated release matrix 39133504297 is still running." + "2026-10-18T14:11:46.956Z",codex-agent,"New open GitHub issue #85 names PR #84 and is in review-round scope. Read the complete issue and independently confirmed raw approval spelling in reservation matching, promotion counting and persistence. Fix canonical SDK Decision identity for new promotions, historical promoted aliases, reservation references and loop replay; test full, uppercase and short references with zero/free capacity, mixed-alias concurrency, manual promotion, canonical persistence, legacy records and fail-closed unresolved evidence. Existing eab900b gates do not certify this new change." + "2026-10-18T14:15:16.820Z",codex-agent,"Issue #85 alias fix passes 2/2 through the pinned PM runner on SDK 2026.10.13. Full/uppercase/short references share one canonical Decision for reservation matching, historic promotion counting and new persistence. Real loop/manual requests refuse when all four slots are reserved; mixed-alias contenders share only one free slot. Legacy generation/reservation aliases count, owner/terminal replay adds no jobs, missing/wrong-type historic approval references fail closed. Behavioral revert of only the changed identity-handling functions to eab900b, with both new tests retained, fails 0/2; restoration passes 2/2. Total behavioral revert proofs now 23. Earlier eab900b matrix 39133504297 passed all three variants 626/626, four coverage metrics 100%, 35 sources / 295 documented declarations; this does not certify the alias change. Complete meta/lineage suite is running and fresh full gates will run on the next pushed head." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project @@ -84,7 +87,7 @@ files[24]{path,scope}: test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[10]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[12]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop @@ -95,6 +98,8 @@ tests[10]{command,scope,timeout_seconds,provenance{author,created_at,source_kind "node --test --test-name-pattern=\"ambiguous outer meta|shared inner promotion|promotion headroom counts|inner promotion-budget\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T12:15:16.768Z",local_mutation,feat/meta-recursive-recipe-loop node --test test/meta.test.ts,project,600,codex-agent,"2026-10-18T12:46:31.272Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"mixed-case excluded|ordinary concurrent|operational and unclassified|published meta\" test/dataset.test.ts test/meta.test.ts",project,600,codex-agent,"2026-10-18T13:51:45.650Z",local_mutation,feat/meta-recursive-recipe-loop + "node --test --test-name-pattern=\"approval aliases\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T14:14:11.328Z",local_mutation,feat/meta-recursive-recipe-loop + node --test test/meta.test.ts test/lineage.test.ts,project,600,codex-agent,"2026-10-18T14:14:58.098Z",local_mutation,feat/meta-recursive-recipe-loop docs[7]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 102152b3..9124476e 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -84,3 +84,8 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T13:51:44.304Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/44","value":{"created_at":"2026-10-18T13:51:44.304Z","author":"codex-agent","text":"All four findings verified and fixed: casefold excluded remotes before metadata/history; shared writer-locked promotion accounting preserves unconsumed meta reservations for their owner; package includes the linked sanity receipt; only explicit candidate-contamination promotion refusals may retain policy evidence. Revert proofs with regressions retained: remove casefold -> mixed-case test 0/1; remove promoteGenerationCore retained-capacity check -> ordinary concurrency test 0/1 (two promotions instead of one); remove packaged receipt -> dry-run tarball test 0/1; restore old fitRecipe refusal guard -> operational-refusal test 0/1 (missing rejection). Restored new regressions 4/4. No live rerun or thresholds changed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:51:44.304Z"}],"before_hash":"4ce11016db7b4ede76650fb6e879dd8e3f41fdcf2f085e4055041b61e1e211e0","after_hash":"6427b54eb49212d651dd9581beea3df4307eea71bdb832d640b49db7842889b2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c791c2858b8046e18607ad293abe741ea6de1840478b3cb5b9a27865497aafb9"} {"hash_algorithm":"sha256","ts":"2026-10-18T13:51:45.683Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/9","value":{"command":"node --test --test-name-pattern=\"mixed-case excluded|ordinary concurrent|operational and unclassified|published meta\" test/dataset.test.ts test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T13:51:45.650Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:51:45.683Z"}],"before_hash":"6427b54eb49212d651dd9581beea3df4307eea71bdb832d640b49db7842889b2","after_hash":"56d987ca892d90ed363474dc8e65c98d86a73232835cc2d9f6cb8249cf115d85","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fe32fa16f61d66edf3d8e01d942f26428e262a393c28d58f2fcbef6a33ddb1c9"} {"hash_algorithm":"sha256","ts":"2026-10-18T13:52:41.064Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/45","value":{"created_at":"2026-10-18T13:52:41.064Z","author":"codex-agent","text":"Focused restored regressions pass 4/4 through the pinned PM runner. Typecheck, build, test compilation, lint, zero-duplication gate, docstrings (35 sources / 295 documented declarations), and changelog checks pass. The complete linked meta suite is running; complete npm and Bun release gates will be verified in the isolated CI matrix. A comma-separated bare files argument was correctly refused; repeated --add flags were used instead. Existing file links were retained."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:52:41.064Z"}],"before_hash":"56d987ca892d90ed363474dc8e65c98d86a73232835cc2d9f6cb8249cf115d85","after_hash":"94509b90d23e8935bb74bea4403cb3e0987ef6f939b8a07340e0dc3a04a55757","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"750035e33123dc89a3810a6d2e1dbc35ccbf0848fa90ad664d53ecdbeddb31da"} +{"hash_algorithm":"sha256","ts":"2026-10-18T13:59:51.977Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/46","value":{"created_at":"2026-10-18T13:59:51.977Z","author":"codex-agent","text":"Pushed eab900b02d1652884bdde10f12499340005cd4ed and replied to all four threads after push. CodeRabbit independently inspected each fix and resolved its own four threads, explicitly without rerunning tests or verifying pending CI. Complete linked meta suite passes 26/26 in 122216 ms with no failures/skips. Fresh no-local clone strict health with merge drivers passes; three existing telemetry/staleness/provenance advisories remain. All main-branch history prefixes and public-path privacy checks pass. Frozen live and sanity receipts are unchanged. Complete isolated release matrix 39133504297 is still running."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T13:59:51.977Z"}],"before_hash":"94509b90d23e8935bb74bea4403cb3e0987ef6f939b8a07340e0dc3a04a55757","after_hash":"e40418e4128c785f27b20b5d91da2490caf7600af7ba023349e705567950a959","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"267993953f1cc39b834ecdf23daec0e47086cf688b656c474c109117fed14c1d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:11:46.956Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/47","value":{"created_at":"2026-10-18T14:11:46.956Z","author":"codex-agent","text":"New open GitHub issue #85 names PR #84 and is in review-round scope. Read the complete issue and independently confirmed raw approval spelling in reservation matching, promotion counting and persistence. Fix canonical SDK Decision identity for new promotions, historical promoted aliases, reservation references and loop replay; test full, uppercase and short references with zero/free capacity, mixed-alias concurrency, manual promotion, canonical persistence, legacy records and fail-closed unresolved evidence. Existing eab900b gates do not certify this new change."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:11:46.956Z"}],"before_hash":"e40418e4128c785f27b20b5d91da2490caf7600af7ba023349e705567950a959","after_hash":"29a6171062ecb050b942390649b2077f94813f491918e5758881f3385ea94f28","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"843a0c21a014a459da7f71cfd4e6e6fe66ca02090cd2eddcf2d9c3205dc59b5c"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:14:11.376Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/10","value":{"command":"node --test --test-name-pattern=\"approval aliases\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T14:14:11.328Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:14:11.376Z"}],"before_hash":"29a6171062ecb050b942390649b2077f94813f491918e5758881f3385ea94f28","after_hash":"8766ede764a354893f77ef8b4c3aab3358ff2aa5f70690a7f81df916ec137b06","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"74175b924519bbb7e9ec798aa6bd391bfa975bc31f7404a0bb506019334e1c94"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:14:58.130Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/11","value":{"command":"node --test test/meta.test.ts test/lineage.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T14:14:58.098Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:14:58.130Z"}],"before_hash":"8766ede764a354893f77ef8b4c3aab3358ff2aa5f70690a7f81df916ec137b06","after_hash":"90ff4b44e03152b443b9fcc29ea108c8f4901524c1eccf8ecf3c7d3901f0c221","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"905770136baabc29abcbdb36c3d6ea2fad8b3a827f4a16f18c976347edc9e19c"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:15:16.820Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/48","value":{"created_at":"2026-10-18T14:15:16.820Z","author":"codex-agent","text":"Issue #85 alias fix passes 2/2 through the pinned PM runner on SDK 2026.10.13. Full/uppercase/short references share one canonical Decision for reservation matching, historic promotion counting and new persistence. Real loop/manual requests refuse when all four slots are reserved; mixed-alias contenders share only one free slot. Legacy generation/reservation aliases count, owner/terminal replay adds no jobs, missing/wrong-type historic approval references fail closed. Behavioral revert of only the changed identity-handling functions to eab900b, with both new tests retained, fails 0/2; restoration passes 2/2. Total behavioral revert proofs now 23. Earlier eab900b matrix 39133504297 passed all three variants 626/626, four coverage metrics 100%, 35 sources / 295 documented declarations; this does not certify the alias change. Complete meta/lineage suite is running and fresh full gates will run on the next pushed head."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:15:16.820Z"}],"before_hash":"90ff4b44e03152b443b9fcc29ea108c8f4901524c1eccf8ecf3c7d3901f0c221","after_hash":"5e067e25574755a249d075f23d445f97016ef35b432b4147b1a5fbc6f40bbf71","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"058023064e5c872374616d5fa4c954272da47ce1723e7f2814e48cd7f2d4f567"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 35ad3eb0..61631d17 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -106,7 +106,11 @@ Adapters report structured progress and completion evidence over a documented st refusals cannot become recipe evidence on replay. Mixed-case excluded remotes refuse before metadata/history reads, and the package ships the linked sanity receipt. Four additional behavioral reverts fail; restored regressions pass 4/4. - Live receipts and promotion thresholds remain unchanged. + Live receipts and promotion thresholds remain unchanged. Approval references + resolve to canonical SDK Decision identities for shared accounting and new + promotions; existing alias records count against the same budget, and + unreadable identities refuse. Issue #85 retains pinned-SDK alias regressions + and their behavior-only revert proof. ## Data boundary and capacity diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index c794f28c..661999df 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -297,3 +297,14 @@ Four independent behavior-only reverts fail the new regressions; restoring the fixes passes 4/4. The frozen real-data and known-signal receipts are unchanged. Complete release-gate verification for this review head is recorded in the PR and PM item after CI finishes. + +Issue [#85](https://github.com/unbraind/pm-rl/issues/85) additionally verifies +canonical approval identity. Full, uppercase and short SDK references identify +one Decision for reservation matching, consumed-promotion counting and new +promotion persistence. Historical promoted and reservation references resolve +through that same SDK boundary; an unreadable or wrong-type reference refuses. +Loop replay compares canonical identities without rewriting historical receipts. +Pinned-SDK regressions cover ordinary/manual promotion with all capacity held, +concurrent mixed aliases with one free slot, canonical new records, legacy alias +records, owner resume and terminal replay without extra process charges. Restoring +only the changed identity-handling functions fails both regressions (0/2). diff --git a/index.ts b/index.ts index dc96abb9..9385c4b1 100644 --- a/index.ts +++ b/index.ts @@ -1968,10 +1968,11 @@ async function buildAncestry(client: PmClient, headId: string, strict: boolean): * @throws When any generation's specification cannot be read or parsed. */ export async function promotedGenerationIdsUnderApproval(client: PmClient, approvalId: string): Promise { - // Bodies come back with the listing. Callers hold the SDK writer - // lock, so a per-record `client.get` would make the critical section grow one - // read per historical generation, and a large enough lineage would turn a - // correct refusal into a lock-wait timeout for every concurrent promoter. + // Generation bodies come back with the listing. Callers hold the writer lock; + // resolve each distinct recorded approval spelling once, caching its canonical + // identity rather than fetching an approval for every historical generation. + const canonical = (await readApprovalSpec(client, approvalId)).id; + const identities = new Map([[canonical, canonical], [approvalId, canonical]]); const result = await client.list({ type: "Generation", status: "all", noTruncate: true, fields: "id,body" }); const promoted: string[] = []; for (const item of result.items) { @@ -1989,7 +1990,15 @@ export async function promotedGenerationIdsUnderApproval(client: PmClient, appro } catch (error) { fail(`Promotion refused: generation ${item.id} has an unparseable specification (${String(error)}), so the approved budget cannot be established.`, "budget_undecidable", EXIT_CODE.CONFLICT); } - if (spec.promoted && spec.approval === approvalId) promoted.push(item.id); + if (spec.promoted && spec.approval !== null) { + let identity = identities.get(spec.approval); + if (identity === undefined) { + try { identity = (await readApprovalSpec(client, spec.approval)).id; } + catch (error) { fail(`Promotion refused: generation ${item.id} has an unreadable approval (${String(error)}), so the approved budget cannot be established.`, "budget_undecidable", EXIT_CODE.CONFLICT); } + identities.set(spec.approval, identity); + } + if (identity === canonical) promoted.push(item.id); + } } return promoted; } @@ -2233,9 +2242,9 @@ async function registerGenerationCore(client: PmClient, request: GenerationRegis * * @param client - Client bound to the target workspace. * @param approvalId - The approval Decision item id. - * @returns The parsed approval specification. + * @returns The parsed approval specification and its canonical SDK identity. */ -async function readApprovalSpec(client: PmClient, approvalId: string): Promise { +export async function readApprovalSpec(client: PmClient, approvalId: string): Promise { const approval = await client.get(approvalId, { depth: "deep" }); if (String(approval.item.type) !== "Decision") { fail(`pm rl expected a Decision ${approvalId} as the approval item, not ${String(approval.item.type)}.`, "wrong_approval_type", EXIT_CODE.CONFLICT); @@ -2244,7 +2253,9 @@ async function readApprovalSpec(client: PmClient, approvalId: string): Promise { const promotedSpec: GenerationSpec = { ...base, promoted: true, - approval: approvalId, + approval: canonicalApprovalId, proxy_score: proxyScore, held_out_score: heldOutScore, gap, @@ -2459,9 +2471,10 @@ async function promoteGenerationCore(client: PmClient, coordinates: WorkspaceCoo // is a comparison between two values, and re-reading only one of them // leaves the comparison stale in the other direction. const lockedApprovalSpec = await readApprovalSpec(client, approvalId); - const promotedIds = await promotedGenerationIdsUnderApproval(client, approvalId); + canonicalApprovalId = lockedApprovalSpec.id; + const promotedIds = await promotedGenerationIdsUnderApproval(client, canonicalApprovalId); promotedCount = promotedIds.length; - const retainedHeadroom = await retainedMetaPromotionHeadroom(client, approvalId, promotedIds, String(current.item.id)); + const retainedHeadroom = await retainedMetaPromotionHeadroom(client, canonicalApprovalId, promotedIds, String(current.item.id)); permittedPromotions = lockedApprovalSpec.permitted_promotions; if (promotedCount + retainedHeadroom >= permittedPromotions) { fail(`Advancing past the approved promotion budget is refused. ${promotedCount} promotion(s) consumed; ${retainedHeadroom} promotion(s) held for meta search; approval ${approvalId} permits ${permittedPromotions}. Extend approval item ${approvalId} to authorize more promotions.`, "budget_exceeded", EXIT_CODE.CONFLICT); @@ -3342,8 +3355,8 @@ async function findGenerationItems(client: PmClient, id: string, generation: num } /** Verify a promoted generation's recorded approval matches the approval governing this execution. */ -function verifyLoopApproval(governing: string, recorded: string | null, id: string, generation: number): void { - if (governing.length > 0 && recorded !== null && recorded !== governing) { +async function verifyLoopApproval(client: PmClient, governing: string, recorded: string | null, id: string, generation: number): Promise { + if (governing.length > 0 && recorded !== null && (await readApprovalSpec(client, recorded)).id !== (await readApprovalSpec(client, governing)).id) { fail(`Loop ${id} generation ${generation} was promoted under approval ${recorded}, not the requested ${governing}; the promotion budget governing this loop cannot be switched mid-lineage.`, "loop_approval_mismatch", EXIT_CODE.CONFLICT); } } @@ -3593,7 +3606,7 @@ async function inspectCandidateVerdict(client: PmClient, programme: LoopProgramm const report: RlLoopGenerationReport = { generation, run: runId, item: String(item.item.id), promoted: spec.promoted, held_out_mean: verified.candidateHeldOutMean, candidate_checkpoint: verified.candidate.digest, refusal_reason: null }; if (spec.promoted) { - verifyLoopApproval(request.approval, spec.approval, request.id, generation); + await verifyLoopApproval(client, request.approval, spec.approval, request.id, generation); return { kind: "complete", report, advance: { checkpoint: verified.candidate, parent: String(item.item.id), step: deriveNextStepConfig(programme.config, chain.step, verified.candidateHeldOutMean - verified.incumbentHeldOutMean), cost: generationCost(programme) } }; } diff --git a/meta.ts b/meta.ts index d6c0069b..bb0360b3 100644 --- a/meta.ts +++ b/meta.ts @@ -2,7 +2,7 @@ import assert from "node:assert/strict"; import type { PmClient } from "@unbrained/pm-cli/sdk/core"; import { certifyCompleteListResult, EXIT_CODE, isPmCliExpectedError } from "@unbrained/pm-cli/sdk/runtime"; -import { hashJson, commitProcessTransaction, promotedGenerationIdsUnderApproval, readCompleteLoopItem, withRlController, type JsonValue, type RlDurableStep } from "./index.ts"; +import { hashJson, commitProcessTransaction, promotedGenerationIdsUnderApproval, readApprovalSpec, readCompleteLoopItem, withRlController, type JsonValue, type RlDurableStep } from "./index.ts"; import { parseApprovalSpec } from "./lineage.ts"; import { openTrackerEnvironment } from "./tracker-environment.ts"; import { parseProcessAdapter, type ProcessAdapter, type ProcessCoordinates } from "./process.ts"; @@ -119,12 +119,13 @@ async function readMetaReceipt(client: PmClient, key: string) { /** Read canonical reservation records for one approval, ignoring foreign copies and unrelated Decisions. */ async function metaReservations(client: PmClient, approval: string): Promise> }[]> { const items = certifyCompleteListResult(await client.listAllComplete({ includeBody: false })); + const canonical = (await readApprovalSpec(client, approval)).id; const reservations: { prefix: string; record: NonNullable> }[] = []; for (const item of items.items.filter((entry) => entry.type === "Decision" && entry.id.endsWith("-reservation"))) { const record = metaReservation(String((await readCompleteLoopItem(client, item.id)).item.body)); if (record === null) continue; const identity = record.id.toLowerCase(); - if ((item.id === identity || item.id.endsWith(`-${identity}`)) && record.approval === approval) { + if ((item.id === identity || item.id.endsWith(`-${identity}`)) && (await readApprovalSpec(client, record.approval)).id === canonical) { reservations.push({ prefix: item.id.slice(0, -"-reservation".length), record }); } } @@ -164,7 +165,10 @@ async function reserveMeta(client: PmClient, coordinates: ProcessCoordinates, re assert.equal(record.binding, binding, "meta_reservation_drift"); assert.equal(record.format, "pm-rl/meta-reservation/1", "meta_reservation_drift"); assert.equal(record.id, key, "meta_reservation_drift"); - assert.equal(record.approval, (await metaApproval(client, request.approval)).id, "meta_reservation_drift"); + let recordedApproval: string; + try { recordedApproval = (await readApprovalSpec(client, record.approval)).id; } + catch (error) { throw new Error("meta_reservation_drift", { cause: error }); } + assert.equal(recordedApproval, (await metaApproval(client, request.approval)).id, "meta_reservation_drift"); assert.equal(hashJson(record.charge), hashJson(charge), "meta_reservation_drift"); assert.equal(record.promotion_headroom, promotionHeadroom, "meta_reservation_drift"); return { state: "applied" }; diff --git a/test/meta.test.ts b/test/meta.test.ts index abe7db52..0b4f5e7a 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -10,7 +10,7 @@ import { test } from "node:test"; import { createExtensionTestHarness } from "@unbrained/pm-cli/sdk/testing"; import { acquireLock, certifyCompleteListResult } from "@unbrained/pm-cli/sdk/runtime"; import extension, { hashJson, runRlLoop, promotedGenerationIdsUnderApproval, type JsonValue, type RlCommandResult, loopLeaseLockId, loopProcessStartTime, LOOP_LEASE_TTL_SECONDS, RL_COMMANDS } from "../index.ts"; -import { compareRecipes, durableRecipeProposals, metaReservation, parseMetaConfig, proposeRecipes, recipeExamples, recipeSuccessor, runRlMeta, scoreTrackerPolicy, type MetaConfig, type MetaRequest } from "../meta.ts"; +import { compareRecipes, durableRecipeProposals, metaReservation, parseMetaConfig, proposeRecipes, recipeExamples, recipeSuccessor, runRlMeta, scoreTrackerPolicy, retainedMetaPromotionHeadroom, type MetaConfig, type MetaRequest } from "../meta.ts"; import { INITIAL_RECIPE, recipeArtifact, seededRecipes } from "../recipe.ts"; import { banditCheckpoint } from "../bandit.ts"; import { readTrackerSplit, type TrackerDataset, type TrackerExample, TRACKER_SPLITS } from "../dataset.ts"; @@ -171,6 +171,67 @@ test("ordinary concurrent promotions preserve retained meta capacity until its o assert.deepEqual(await listProcessJobs(w.client), jobs); }); +test("approval aliases cannot spend retained meta capacity through ordinary or manual promotion", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const aliases = [w.approval, w.approval.toUpperCase(), "approval"]; + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: 4 })}\n\`\`\`` }); + const request = { ...requestFor(w, "alias-owner", { ...metaConfig, meta_generations: 1, candidates: 1 }), approval: "approval" }; + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, onStep(key) { if (key === "programme") throw new Error("alias capacity held"); } }), /alias capacity held/); + const harness = await createExtensionTestHarness(extension, { name: "pm-rl", capabilities: ["commands", "hooks", "schema"] }); + const scores = join(w.root, "manual-scores.json"); + const score = { objective: "episode_return", objective_version: "1", evaluation_context: "synthetic-manual-held-out", seed_set: "synthetic", direction: "maximize", scale: 1, value: 1 }; + writeFileSync(scores, JSON.stringify({ proxy_score: score, held_out_score: score })); + const raw = JSON.parse(readFileSync(new URL("../examples/loop-bandit.json", import.meta.url), "utf8")) as Record; + for (const [index, approval] of aliases.entries()) { + assert.equal((await w.client.get(approval)).item.id, w.approval); + assert.equal(await retainedMetaPromotionHeadroom(w.client, approval, []), 4); + const report = await runRlLoop(w.client, w.coordinates, { id: `alias-out-${index}`, config: { ...raw, max_generations: 1 }, approval }); + assert.equal(report.promoted, 0); assert.match(report.refusal_reason!, /approved promotion budget/); + await assert.rejects(harness.runCommand({ command: "rl generation promote", pmRoot: w.coordinates.pmRoot, + args: [report.generations[0].item], options: { approval, scores, evidence: "synthetic alias budget check" } }), /approved promotion budget/); + } + const report = await runRlMeta(w.client, w.coordinates, { ...request, approval: w.approval.toUpperCase() }); + assert.equal(report.generations.length, 1); + const jobs = await listProcessJobs(w.client); + assert.deepEqual(await runRlMeta(w.client, w.coordinates, { ...request, approval: w.approval }), report); + assert.deepEqual(await listProcessJobs(w.client), jobs); +}); + +test("mixed approval aliases share one free slot and count legacy alias records on resume", { timeout: 600_000 }, async () => { + const w = await metaWorkspace(); const aliases = [w.approval, w.approval.toUpperCase(), "approval"]; + await w.client.update(w.approval, { body: `\`\`\`json\n${JSON.stringify({ ...metaSpec, permitted_promotions: 5 })}\n\`\`\`` }); + const request = requestFor(w, "mixed-owner", { ...metaConfig, meta_generations: 1, candidates: 1 }); + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, onStep(key) { if (key === "programme") throw new Error("mixed capacity held"); } }), /mixed capacity held/); + const reservation = await w.client.get("mixed-owner-reservation"); + await w.client.update(reservation.item.id, { body: JSON.stringify({ ...JSON.parse(String(reservation.item.body)) as Record, approval: "approval" }) }); + const raw = JSON.parse(readFileSync(new URL("../examples/loop-bandit.json", import.meta.url), "utf8")) as Record; + const requests = aliases.map((approval, index) => ({ id: `mixed-out-${index}`, config: { ...raw, max_generations: 1 }, approval })); + const reports = await Promise.all(requests.map((request) => runRlLoop(w.client, w.coordinates, request))); + assert.equal(reports.reduce((sum, report) => sum + report.promoted, 0), 1); + const winner = reports.findIndex((report) => report.promoted === 1); + const generation = await w.client.get(reports[winner].generations[0].item); + const fence = /```json\n([\s\S]+?)\n```/.exec(String(generation.item.body))!; + const spec = JSON.parse(fence[1]) as Record; + assert.equal(spec.approval, w.approval, "new promotions persist the canonical Decision identity"); + for (const approval of aliases) { + await w.client.update(generation.item.id, { body: `\`\`\`json\n${JSON.stringify({ ...spec, approval })}\n\`\`\`` }); + for (const reference of aliases) { + assert.deepEqual(await promotedGenerationIdsUnderApproval(w.client, reference), [generation.item.id]); + assert.equal(await retainedMetaPromotionHeadroom(w.client, reference, [generation.item.id]), 4); + } + assert.equal((await runRlLoop(w.client, w.coordinates, requests[winner])).promoted, 1); + } + await assert.rejects(runRlMeta(w.client, w.coordinates, { ...request, id: "aliases-exhausted", approval: "approval" }), /meta_promotion_budget_exhausted/); + const report = await runRlMeta(w.client, w.coordinates, { ...request, approval: "approval" }); + assert.equal(report.generations.length, 1); + const jobs = await listProcessJobs(w.client); + assert.deepEqual(await runRlMeta(w.client, w.coordinates, request), report); + assert.deepEqual(await listProcessJobs(w.client), jobs); + for (const approval of ["missing-approval", (await w.client.create({ type: "Task", title: "Unusable legacy approval" })).item.id]) { + await w.client.update(generation.item.id, { body: `\`\`\`json\n${JSON.stringify({ ...spec, approval })}\n\`\`\`` }); + await assert.rejects(promotedGenerationIdsUnderApproval(w.client, w.approval), /approved budget cannot be established/); + } +}); + test("inner promotion-budget refusals never become recipe evidence, including after an accepted generation", { timeout: 600_000 }, async () => { for (const permitted of [0, 1]) { const w = await metaWorkspace(); From 5c9ab9a2a756bf626443b53f56127738ea85ef36 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:16:15 +0200 Subject: [PATCH 20/24] refactor: rely on validated SDK approval identities --- .agents/pm/features/pm-rl-meta.toon | 5 +++-- .agents/pm/history/pm-rl-meta.jsonl | 1 + index.ts | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index c686027f..ac8bf849 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T14:15:16.820Z" +updated_at: "2026-10-18T14:16:11.994Z" assignee: codex-agent claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[49]{created_at,author,text}: +comments[50]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -62,6 +62,7 @@ comments[49]{created_at,author,text}: "2026-10-18T13:59:51.977Z",codex-agent,"Pushed eab900b02d1652884bdde10f12499340005cd4ed and replied to all four threads after push. CodeRabbit independently inspected each fix and resolved its own four threads, explicitly without rerunning tests or verifying pending CI. Complete linked meta suite passes 26/26 in 122216 ms with no failures/skips. Fresh no-local clone strict health with merge drivers passes; three existing telemetry/staleness/provenance advisories remain. All main-branch history prefixes and public-path privacy checks pass. Frozen live and sanity receipts are unchanged. Complete isolated release matrix 39133504297 is still running." "2026-10-18T14:11:46.956Z",codex-agent,"New open GitHub issue #85 names PR #84 and is in review-round scope. Read the complete issue and independently confirmed raw approval spelling in reservation matching, promotion counting and persistence. Fix canonical SDK Decision identity for new promotions, historical promoted aliases, reservation references and loop replay; test full, uppercase and short references with zero/free capacity, mixed-alias concurrency, manual promotion, canonical persistence, legacy records and fail-closed unresolved evidence. Existing eab900b gates do not certify this new change." "2026-10-18T14:15:16.820Z",codex-agent,"Issue #85 alias fix passes 2/2 through the pinned PM runner on SDK 2026.10.13. Full/uppercase/short references share one canonical Decision for reservation matching, historic promotion counting and new persistence. Real loop/manual requests refuse when all four slots are reserved; mixed-alias contenders share only one free slot. Legacy generation/reservation aliases count, owner/terminal replay adds no jobs, missing/wrong-type historic approval references fail closed. Behavioral revert of only the changed identity-handling functions to eab900b, with both new tests retained, fails 0/2; restoration passes 2/2. Total behavioral revert proofs now 23. Earlier eab900b matrix 39133504297 passed all three variants 626/626, four coverage metrics 100%, 35 sources / 295 documented declarations; this does not certify the alias change. Complete meta/lineage suite is running and fresh full gates will run on the next pushed head." + "2026-10-18T14:16:11.994Z",codex-agent,"Approval canonical identity uses the pinned SDK validated get result and its statically required item.id; unreadable/missing/wrong-type references fail at that boundary. Removed an unreachable duplicate shape guard rather than adding SDK mocks solely to cover it. Identity normalization, canonical persistence and fail-closed accounting are unchanged. Issue #85 reply and Fixes clause follow the pushed fix." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index 9124476e..a6e74b31 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -89,3 +89,4 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T14:14:11.376Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/10","value":{"command":"node --test --test-name-pattern=\"approval aliases\" test/meta.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T14:14:11.328Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:14:11.376Z"}],"before_hash":"29a6171062ecb050b942390649b2077f94813f491918e5758881f3385ea94f28","after_hash":"8766ede764a354893f77ef8b4c3aab3358ff2aa5f70690a7f81df916ec137b06","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"74175b924519bbb7e9ec798aa6bd391bfa975bc31f7404a0bb506019334e1c94"} {"hash_algorithm":"sha256","ts":"2026-10-18T14:14:58.130Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/11","value":{"command":"node --test test/meta.test.ts test/lineage.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T14:14:58.098Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:14:58.130Z"}],"before_hash":"8766ede764a354893f77ef8b4c3aab3358ff2aa5f70690a7f81df916ec137b06","after_hash":"90ff4b44e03152b443b9fcc29ea108c8f4901524c1eccf8ecf3c7d3901f0c221","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"905770136baabc29abcbdb36c3d6ea2fad8b3a827f4a16f18c976347edc9e19c"} {"hash_algorithm":"sha256","ts":"2026-10-18T14:15:16.820Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/48","value":{"created_at":"2026-10-18T14:15:16.820Z","author":"codex-agent","text":"Issue #85 alias fix passes 2/2 through the pinned PM runner on SDK 2026.10.13. Full/uppercase/short references share one canonical Decision for reservation matching, historic promotion counting and new persistence. Real loop/manual requests refuse when all four slots are reserved; mixed-alias contenders share only one free slot. Legacy generation/reservation aliases count, owner/terminal replay adds no jobs, missing/wrong-type historic approval references fail closed. Behavioral revert of only the changed identity-handling functions to eab900b, with both new tests retained, fails 0/2; restoration passes 2/2. Total behavioral revert proofs now 23. Earlier eab900b matrix 39133504297 passed all three variants 626/626, four coverage metrics 100%, 35 sources / 295 documented declarations; this does not certify the alias change. Complete meta/lineage suite is running and fresh full gates will run on the next pushed head."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:15:16.820Z"}],"before_hash":"90ff4b44e03152b443b9fcc29ea108c8f4901524c1eccf8ecf3c7d3901f0c221","after_hash":"5e067e25574755a249d075f23d445f97016ef35b432b4147b1a5fbc6f40bbf71","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"058023064e5c872374616d5fa4c954272da47ce1723e7f2814e48cd7f2d4f567"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:16:11.994Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/49","value":{"created_at":"2026-10-18T14:16:11.994Z","author":"codex-agent","text":"Approval canonical identity uses the pinned SDK validated get result and its statically required item.id; unreadable/missing/wrong-type references fail at that boundary. Removed an unreachable duplicate shape guard rather than adding SDK mocks solely to cover it. Identity normalization, canonical persistence and fail-closed accounting are unchanged. Issue #85 reply and Fixes clause follow the pushed fix."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:16:11.994Z"}],"before_hash":"5e067e25574755a249d075f23d445f97016ef35b432b4147b1a5fbc6f40bbf71","after_hash":"86ebf1b3745eab5bdd286c90256a19d9b992499e027c1d7cadc9fe698794744f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0d216838e92287bb3a633ba7e6a431ae19fce99da7344ed31c755f1e85bd6ac9"} diff --git a/index.ts b/index.ts index 9385c4b1..7dbc55cd 100644 --- a/index.ts +++ b/index.ts @@ -2254,7 +2254,6 @@ export async function readApprovalSpec(client: PmClient, approvalId: string): Pr fail(`Approval item ${approvalId} has no JSON specification fence.`, "approval_missing_spec", EXIT_CODE.CONFLICT); } const id = approval.item.id; - if (typeof id !== "string" || id.length === 0) fail("The approval identity cannot be established.", "approval_identity_unreadable", EXIT_CODE.CONFLICT); return { ...parseApprovalSpec(approvalFenced[1], `Approval ${approvalId}`), id }; } From ef8210b1a1d534653c6d2d5194de699a584381c7 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:35:16 +0200 Subject: [PATCH 21/24] docs: record verified review gates and alias regression evidence --- .agents/pm/features/pm-rl-meta.toon | 13 +++++++------ .agents/pm/history/pm-rl-meta.jsonl | 6 ++++++ RECURSIVE_TRAINING.md | 11 +++++++---- docs/meta-recursive.md | 28 ++++++++++++++++++++-------- test/meta.test.ts | 3 ++- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index ac8bf849..0c894a58 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T14:16:11.994Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T14:35:06.415Z" author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[50]{created_at,author,text}: +comments[54]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -63,6 +61,10 @@ comments[50]{created_at,author,text}: "2026-10-18T14:11:46.956Z",codex-agent,"New open GitHub issue #85 names PR #84 and is in review-round scope. Read the complete issue and independently confirmed raw approval spelling in reservation matching, promotion counting and persistence. Fix canonical SDK Decision identity for new promotions, historical promoted aliases, reservation references and loop replay; test full, uppercase and short references with zero/free capacity, mixed-alias concurrency, manual promotion, canonical persistence, legacy records and fail-closed unresolved evidence. Existing eab900b gates do not certify this new change." "2026-10-18T14:15:16.820Z",codex-agent,"Issue #85 alias fix passes 2/2 through the pinned PM runner on SDK 2026.10.13. Full/uppercase/short references share one canonical Decision for reservation matching, historic promotion counting and new persistence. Real loop/manual requests refuse when all four slots are reserved; mixed-alias contenders share only one free slot. Legacy generation/reservation aliases count, owner/terminal replay adds no jobs, missing/wrong-type historic approval references fail closed. Behavioral revert of only the changed identity-handling functions to eab900b, with both new tests retained, fails 0/2; restoration passes 2/2. Total behavioral revert proofs now 23. Earlier eab900b matrix 39133504297 passed all three variants 626/626, four coverage metrics 100%, 35 sources / 295 documented declarations; this does not certify the alias change. Complete meta/lineage suite is running and fresh full gates will run on the next pushed head." "2026-10-18T14:16:11.994Z",codex-agent,"Approval canonical identity uses the pinned SDK validated get result and its statically required item.id; unreadable/missing/wrong-type references fail at that boundary. Removed an unreachable duplicate shape guard rather than adding SDK mocks solely to cover it. Identity normalization, canonical persistence and fail-closed accounting are unchanged. Issue #85 reply and Fixes clause follow the pushed fix." + "2026-10-18T14:18:27.898Z",codex-agent,"The combined linked meta/lineage attempt reported 40/79 passing and 39 lineage setup failures: known PM sandbox PM_PATH injection redirected legacy tracker init to existing schema settings (init_existing_settings_requires_force). All 28 meta cases passed; this is not a full combined-suite success. Remove the unsuitable combined command link while retaining this failed receipt in append-only history; run legacy lineage directly with isolated identity. Existing follow-up pm-rl-warf covers this limitation. No new SDK bug is filed." + "2026-10-18T14:22:26.643Z",codex-agent,"Direct isolated lineage suite passes 51/51, zero failures/skips, in 62528.75 ms. The failed combined PM attempt still contains 28/28 passing meta cases; only legacy lineage tracker setup collided with injected PM_PATH. Fresh no-local clone of 5c9ab9a2a756bf626443b53f56127738ea85ef36 passes strict health with merge drivers and three unchanged advisories. Intermediate 49323f0 CI was canceled after superseding it, so it is not passing evidence. Current complete release matrix 39135240662 and CodeQL run 39135240660 belong to 5c9ab9a; CodeQL passes, release gates remain pending." + "2026-10-18T14:29:06.664Z",codex-agent,"Strengthened the mixed-alias concurrency regression: every contender uses an alias, so canonical persistence cannot pass because a canonical caller won. Independent behavioral proof restores only promoteGenerationCore raw approval persistence; the retained regression fails 0/1 with actual RL-APPROVAL versus expected rl-approval. Restoration passes the pinned linked alias command 2/2 (52006 ms). This is a second issue #85 proof and raises the total to 24. Production code remains exactly 5c9ab9a; the strengthened assertion will be included in the handoff commit and its full CI. Latest origin/main is already contained; canonical checkout is clean; private-path scan passes." + "2026-10-18T14:35:03.715Z",codex-agent,"Complete source gates on 5c9ab9a2a756bf626443b53f56127738ea85ef36: CI 39135240662 passes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME/global/system Git config. Each reports 628/628, 0 failures/cancellations/skips, 100% statements/lines/branches/functions, all 35 declared sources and 295 documented declarations. All logs verify the packaged sanity receipt, zero clones and production audit, changelog and identity checks. CodeQL 39135240660 passes. Revert proofs total 24; alias PM command 2/2, new four-findings command 4/4, direct isolated lineage 51/51; combined-harness setup failure remains explicit. Issue #85 is linked by Fixes in PR body and has a post-push evidence reply. Release stays disabled, no items closed, frozen live/sanity receipts unchanged. Handoff commit includes the stronger alias assertion and these receipts, then receives separate exact-head CI; no final independent review approval is claimed." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project @@ -88,7 +90,7 @@ files[24]{path,scope}: test/meta.test.ts,project test/recipe.test.ts,project tracker-environment.ts,project -tests[12]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: +tests[11]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node --test test/recipe.test.ts test/dataset.test.ts,project,600,codex-agent,"2026-10-18T03:23:50.382Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"one pre-approved|genuinely better|real outer SIGKILL\" test/meta.test.ts",project,900,codex-agent,"2026-10-18T03:50:43.085Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"programme identity cannot hide\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T06:00:04.075Z",local_mutation,feat/meta-recursive-recipe-loop @@ -100,7 +102,6 @@ tests[12]{command,scope,timeout_seconds,provenance{author,created_at,source_kind node --test test/meta.test.ts,project,600,codex-agent,"2026-10-18T12:46:31.272Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"mixed-case excluded|ordinary concurrent|operational and unclassified|published meta\" test/dataset.test.ts test/meta.test.ts",project,600,codex-agent,"2026-10-18T13:51:45.650Z",local_mutation,feat/meta-recursive-recipe-loop "node --test --test-name-pattern=\"approval aliases\" test/meta.test.ts",project,600,codex-agent,"2026-10-18T14:14:11.328Z",local_mutation,feat/meta-recursive-recipe-loop - node --test test/meta.test.ts test/lineage.test.ts,project,600,codex-agent,"2026-10-18T14:14:58.098Z",local_mutation,feat/meta-recursive-recipe-loop docs[7]{path,scope}: docs/durable-systemone-validation.md,project docs/meta-live-evidence.json,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index a6e74b31..eede0734 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -90,3 +90,9 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T14:14:58.130Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/11","value":{"command":"node --test test/meta.test.ts test/lineage.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-agent","created_at":"2026-10-18T14:14:58.098Z","source_kind":"local_mutation","source_ref":"feat/meta-recursive-recipe-loop"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:14:58.130Z"}],"before_hash":"8766ede764a354893f77ef8b4c3aab3358ff2aa5f70690a7f81df916ec137b06","after_hash":"90ff4b44e03152b443b9fcc29ea108c8f4901524c1eccf8ecf3c7d3901f0c221","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"905770136baabc29abcbdb36c3d6ea2fad8b3a827f4a16f18c976347edc9e19c"} {"hash_algorithm":"sha256","ts":"2026-10-18T14:15:16.820Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/48","value":{"created_at":"2026-10-18T14:15:16.820Z","author":"codex-agent","text":"Issue #85 alias fix passes 2/2 through the pinned PM runner on SDK 2026.10.13. Full/uppercase/short references share one canonical Decision for reservation matching, historic promotion counting and new persistence. Real loop/manual requests refuse when all four slots are reserved; mixed-alias contenders share only one free slot. Legacy generation/reservation aliases count, owner/terminal replay adds no jobs, missing/wrong-type historic approval references fail closed. Behavioral revert of only the changed identity-handling functions to eab900b, with both new tests retained, fails 0/2; restoration passes 2/2. Total behavioral revert proofs now 23. Earlier eab900b matrix 39133504297 passed all three variants 626/626, four coverage metrics 100%, 35 sources / 295 documented declarations; this does not certify the alias change. Complete meta/lineage suite is running and fresh full gates will run on the next pushed head."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:15:16.820Z"}],"before_hash":"90ff4b44e03152b443b9fcc29ea108c8f4901524c1eccf8ecf3c7d3901f0c221","after_hash":"5e067e25574755a249d075f23d445f97016ef35b432b4147b1a5fbc6f40bbf71","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"058023064e5c872374616d5fa4c954272da47ce1723e7f2814e48cd7f2d4f567"} {"hash_algorithm":"sha256","ts":"2026-10-18T14:16:11.994Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/49","value":{"created_at":"2026-10-18T14:16:11.994Z","author":"codex-agent","text":"Approval canonical identity uses the pinned SDK validated get result and its statically required item.id; unreadable/missing/wrong-type references fail at that boundary. Removed an unreachable duplicate shape guard rather than adding SDK mocks solely to cover it. Identity normalization, canonical persistence and fail-closed accounting are unchanged. Issue #85 reply and Fixes clause follow the pushed fix."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:16:11.994Z"}],"before_hash":"5e067e25574755a249d075f23d445f97016ef35b432b4147b1a5fbc6f40bbf71","after_hash":"86ebf1b3745eab5bdd286c90256a19d9b992499e027c1d7cadc9fe698794744f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0d216838e92287bb3a633ba7e6a431ae19fce99da7344ed31c755f1e85bd6ac9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:18:27.898Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/50","value":{"created_at":"2026-10-18T14:18:27.898Z","author":"codex-agent","text":"The combined linked meta/lineage attempt reported 40/79 passing and 39 lineage setup failures: known PM sandbox PM_PATH injection redirected legacy tracker init to existing schema settings (init_existing_settings_requires_force). All 28 meta cases passed; this is not a full combined-suite success. Remove the unsuitable combined command link while retaining this failed receipt in append-only history; run legacy lineage directly with isolated identity. Existing follow-up pm-rl-warf covers this limitation. No new SDK bug is filed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:18:27.898Z"}],"before_hash":"86ebf1b3745eab5bdd286c90256a19d9b992499e027c1d7cadc9fe698794744f","after_hash":"85f389af2af19452b9104746bc9e780d9a2affdb7ef525ee4c8638ea6a118ed1","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"1a0e3b9d70ed1ae4b7d962ba369d063abfbc8187ac3dcd75d56c610302f39bde"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:18:28.737Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"tests_remove","patch":[{"op":"remove","path":"/metadata/tests/11"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:18:28.737Z"}],"before_hash":"85f389af2af19452b9104746bc9e780d9a2affdb7ef525ee4c8638ea6a118ed1","after_hash":"9b6e1f5e620b373f7ad6b974948cf824c79900174cded4923d55bf9a4ec43e5f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"44864ea875d056642357fa974571e5a60291cdd818a6e26089e9367f78d61428"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:22:26.643Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/51","value":{"created_at":"2026-10-18T14:22:26.643Z","author":"codex-agent","text":"Direct isolated lineage suite passes 51/51, zero failures/skips, in 62528.75 ms. The failed combined PM attempt still contains 28/28 passing meta cases; only legacy lineage tracker setup collided with injected PM_PATH. Fresh no-local clone of 5c9ab9a2a756bf626443b53f56127738ea85ef36 passes strict health with merge drivers and three unchanged advisories. Intermediate 49323f0 CI was canceled after superseding it, so it is not passing evidence. Current complete release matrix 39135240662 and CodeQL run 39135240660 belong to 5c9ab9a; CodeQL passes, release gates remain pending."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:22:26.643Z"}],"before_hash":"9b6e1f5e620b373f7ad6b974948cf824c79900174cded4923d55bf9a4ec43e5f","after_hash":"9f539d3c19cd081adb6a38397441ab24de4603de4a0d9556cf5740766557960d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f9325a478e49296afea562ac7b3058953c1ddce7f2cdf0686032e0cfc5692108"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:29:06.664Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/52","value":{"created_at":"2026-10-18T14:29:06.664Z","author":"codex-agent","text":"Strengthened the mixed-alias concurrency regression: every contender uses an alias, so canonical persistence cannot pass because a canonical caller won. Independent behavioral proof restores only promoteGenerationCore raw approval persistence; the retained regression fails 0/1 with actual RL-APPROVAL versus expected rl-approval. Restoration passes the pinned linked alias command 2/2 (52006 ms). This is a second issue #85 proof and raises the total to 24. Production code remains exactly 5c9ab9a; the strengthened assertion will be included in the handoff commit and its full CI. Latest origin/main is already contained; canonical checkout is clean; private-path scan passes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:29:06.664Z"}],"before_hash":"9f539d3c19cd081adb6a38397441ab24de4603de4a0d9556cf5740766557960d","after_hash":"a98d6c4f44a2161f45cc0b6c9b4ea3cf697a52a6b76d0f06320693c9d8ed398f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"efa40a7dd9c88933cf8874f2800fd040e1af8eb1bc07b1ba132c540880e20c04"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:35:03.715Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/53","value":{"created_at":"2026-10-18T14:35:03.715Z","author":"codex-agent","text":"Complete source gates on 5c9ab9a2a756bf626443b53f56127738ea85ef36: CI 39135240662 passes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME/global/system Git config. Each reports 628/628, 0 failures/cancellations/skips, 100% statements/lines/branches/functions, all 35 declared sources and 295 documented declarations. All logs verify the packaged sanity receipt, zero clones and production audit, changelog and identity checks. CodeQL 39135240660 passes. Revert proofs total 24; alias PM command 2/2, new four-findings command 4/4, direct isolated lineage 51/51; combined-harness setup failure remains explicit. Issue #85 is linked by Fixes in PR body and has a post-push evidence reply. Release stays disabled, no items closed, frozen live/sanity receipts unchanged. Handoff commit includes the stronger alias assertion and these receipts, then receives separate exact-head CI; no final independent review approval is claimed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:35:03.715Z"}],"before_hash":"a98d6c4f44a2161f45cc0b6c9b4ea3cf697a52a6b76d0f06320693c9d8ed398f","after_hash":"98b1b79a28bacc4f513da03595939a2a7866a0ef43261a00a848609a1564aeab","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"19c69818d34119c182a3e0f47a9531148f6fe9176e6cb444eb7ad2ef85f67a97"} +{"hash_algorithm":"sha256","ts":"2026-10-18T14:35:06.415Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:35:06.415Z"}],"before_hash":"98b1b79a28bacc4f513da03595939a2a7866a0ef43261a00a848609a1564aeab","after_hash":"9377f59ad4975f1e92968806720423c9ceee99ab22a08eef4037d14e56e620f3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"bb2e5009420eeaa39a2b724892248333acea3e3f993aed44ff56c998ea871b00"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 61631d17..996e8ebb 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -86,11 +86,11 @@ Adapters report structured progress and completion evidence over a documented st 0.95-confidence, ten-sample, 0.01-effect gate: gain 0.0686, lower bound 0.036740389785077876, and final-test 5093/10000 to 5806/10000. This is a sanity result, not real-tracker improvement. No gate or real feature was weakened. - [Complete source verification](https://github.com/unbraind/pm-rl/actions/runs/39128976135) + [Complete source verification](https://github.com/unbraind/pm-rl/actions/runs/39135240662) passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: - 622/622 each, zero failures/skips, all four coverage metrics 100% across all + 628/628 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared - budget, conditional promotion and resource-refusal regressions pass; eighteen + budget, conditional promotion and resource-refusal regressions pass; twenty-four behaviour-only reverts fail with tests retained and restored code passes. The review round fixes canonical receipt identity, bounded programme ids and README command syntax; the physical OOM test waits for real daemon evidence @@ -110,7 +110,10 @@ Adapters report structured progress and completion evidence over a documented st resolve to canonical SDK Decision identities for shared accounting and new promotions; existing alias records count against the same budget, and unreadable identities refuse. Issue #85 retains pinned-SDK alias regressions - and their behavior-only revert proof. + and their behavior-only revert proofs. The alias persistence proof forces an + alias caller to win; raw-ID persistence fails the retained assertion. Complete + source verification passes 628/628 in all three release variants, and direct + isolated lineage acceptance passes 51/51. ## Data boundary and capacity diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 661999df..623cffbd 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -209,11 +209,11 @@ predictions, and full disagreement. ## Release verification -The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39128976135) -on `d2de7dc0a4a2cbb7f4ffef33734e5f3d39e5cde6` +The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39135240662) +on `5c9ab9a2a756bf626443b53f56127738ea85ef36` executes `npm run release:check` on Node 22 and 26 and `bun run release:check` on Node 26 with isolated HOME and global/system Git configuration. Each passes -622/622 tests, zero failures/skips, 100% statements/lines/branches/functions over +628/628 tests, zero failures/skips, 100% statements/lines/branches/functions over all 35 declared sources, 295 documented declarations, and zero duplicate clones or production audit findings. Thresholds, dependency pins and release approval are unchanged. The live evidence names the measured production source commit; @@ -231,7 +231,7 @@ remain. Guard-only reverts for recipe lineage, public visibility, programme ids, retained reservation case folding and both resource fault injectors fail; restored implementations pass. PM-linked data/recipe, crash/promotion/budget, identity and resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. The expanded -review command passes 7/7. Eighteen independent behavioral reverts fail across +review command passes 7/7. Twenty-four independent behavioral reverts fail across the feature and subsequent review rounds; restoring the implementations passes. A separate local full-suite attempt hit the unchanged 300-second HTTP crash-drill @@ -276,9 +276,9 @@ removes or damages retained capacity, and requires refusal before any fit starts Restoring the valid reservation resumes without charging it again. Removing only the fenced retained-capacity check fails that regression; restoring it passes. The restored full meta suite passes 23/23 through the pinned PM test runner. -The source-verification matrix above includes this hardening and passes 622/622 +The source-verification matrix above includes this hardening and passes 628/628 in every variant with all four coverage metrics at 100%, 35 sources and 295 -documented declarations. Earlier 621-test receipts remain in PM history at their +documented declarations. Earlier 621-, 622- and 626-test receipts remain in PM history at their exact source heads. The documentation-only handoff commit receives its own complete CI verification; no final-head independent review approval is claimed. @@ -295,8 +295,8 @@ Repository exclusions compare names without case sensitivity before metadata or history reads, and the published package includes both linked evidence receipts. Four independent behavior-only reverts fail the new regressions; restoring the fixes passes 4/4. The frozen real-data and known-signal receipts are unchanged. -Complete release-gate verification for this review head is recorded in the PR -and PM item after CI finishes. +The complete source-verification matrix above passes all three release variants +with 628/628 tests and unchanged thresholds. Issue [#85](https://github.com/unbraind/pm-rl/issues/85) additionally verifies canonical approval identity. Full, uppercase and short SDK references identify @@ -308,3 +308,15 @@ Pinned-SDK regressions cover ordinary/manual promotion with all capacity held, concurrent mixed aliases with one free slot, canonical new records, legacy alias records, owner resume and terminal replay without extra process charges. Restoring only the changed identity-handling functions fails both regressions (0/2). + +The alias concurrency test requires every contender to use an alias; a canonical +caller cannot accidentally satisfy the persistence assertion. Restoring only raw +approval persistence fails 0/1 (`RL-APPROVAL` instead of `rl-approval`); restoring +the fix passes the linked alias command 2/2. The complete meta suite has 28 cases; +direct isolated lineage acceptance passes 51/51. A combined PM-harness attempt +passed its 28 meta cases but hit the known injected-PM_PATH setup collision in 39 +legacy lineage cases. That failed receipt remains in PM history, and the +unsuitable combined link was removed. Both required complete release commands +pass in isolated CI on the source head above. The assertion/documentation handoff +commit receives a separate exact-head CI check; no final-head review approval, +merge or release is implied. diff --git a/test/meta.test.ts b/test/meta.test.ts index 0b4f5e7a..f1c6dcf9 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -204,7 +204,8 @@ test("mixed approval aliases share one free slot and count legacy alias records const reservation = await w.client.get("mixed-owner-reservation"); await w.client.update(reservation.item.id, { body: JSON.stringify({ ...JSON.parse(String(reservation.item.body)) as Record, approval: "approval" }) }); const raw = JSON.parse(readFileSync(new URL("../examples/loop-bandit.json", import.meta.url), "utf8")) as Record; - const requests = aliases.map((approval, index) => ({ id: `mixed-out-${index}`, config: { ...raw, max_generations: 1 }, approval })); + // Every contender uses an alias, so canonical persistence cannot pass merely because the canonical caller won. + const requests = aliases.slice(1).map((approval, index) => ({ id: `mixed-out-${index}`, config: { ...raw, max_generations: 1 }, approval })); const reports = await Promise.all(requests.map((request) => runRlLoop(w.client, w.coordinates, request))); assert.equal(reports.reduce((sum, report) => sum + report.promoted, 0), 1); const winner = reports.findIndex((report) => report.promoted === 1); From 29193adc638a40b04c945e657eaaadfa034a2371 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 17:11:51 +0200 Subject: [PATCH 22/24] fix: report each disagreement peer once after recipe promotion --- .agents/pm/features/pm-rl-meta.toon | 9 +++++++-- .agents/pm/history/pm-rl-meta.jsonl | 4 ++++ RECURSIVE_TRAINING.md | 6 ++++-- docs/meta-recursive.md | 12 +++++++++++- docs/meta-sanity-evidence.json | 24 ++++++------------------ meta.ts | 5 ++++- test/meta.test.ts | 6 ++++++ 7 files changed, 42 insertions(+), 24 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index 0c894a58..fe3e9fe5 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,11 +6,13 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T14:35:06.415Z" +updated_at: "2026-10-18T15:11:48.761Z" +assignee: codex-agent +claim_principal: codex-agent author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[54]{created_at,author,text}: +comments[57]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -65,6 +67,9 @@ comments[54]{created_at,author,text}: "2026-10-18T14:22:26.643Z",codex-agent,"Direct isolated lineage suite passes 51/51, zero failures/skips, in 62528.75 ms. The failed combined PM attempt still contains 28/28 passing meta cases; only legacy lineage tracker setup collided with injected PM_PATH. Fresh no-local clone of 5c9ab9a2a756bf626443b53f56127738ea85ef36 passes strict health with merge drivers and three unchanged advisories. Intermediate 49323f0 CI was canceled after superseding it, so it is not passing evidence. Current complete release matrix 39135240662 and CodeQL run 39135240660 belong to 5c9ab9a; CodeQL passes, release gates remain pending." "2026-10-18T14:29:06.664Z",codex-agent,"Strengthened the mixed-alias concurrency regression: every contender uses an alias, so canonical persistence cannot pass because a canonical caller won. Independent behavioral proof restores only promoteGenerationCore raw approval persistence; the retained regression fails 0/1 with actual RL-APPROVAL versus expected rl-approval. Restoration passes the pinned linked alias command 2/2 (52006 ms). This is a second issue #85 proof and raises the total to 24. Production code remains exactly 5c9ab9a; the strengthened assertion will be included in the handoff commit and its full CI. Latest origin/main is already contained; canonical checkout is clean; private-path scan passes." "2026-10-18T14:35:03.715Z",codex-agent,"Complete source gates on 5c9ab9a2a756bf626443b53f56127738ea85ef36: CI 39135240662 passes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME/global/system Git config. Each reports 628/628, 0 failures/cancellations/skips, 100% statements/lines/branches/functions, all 35 declared sources and 295 documented declarations. All logs verify the packaged sanity receipt, zero clones and production audit, changelog and identity checks. CodeQL 39135240660 passes. Revert proofs total 24; alias PM command 2/2, new four-findings command 4/4, direct isolated lineage 51/51; combined-harness setup failure remains explicit. Issue #85 is linked by Fixes in PR body and has a post-push evidence reply. Release stays disabled, no items closed, frozen live/sanity receipts unchanged. Handoff commit includes the stronger alias assertion and these receipts, then receives separate exact-head CI; no final independent review approval is claimed." + "2026-10-18T15:08:17.679Z",codex-agent,"Review round on ef8210b: read the complete unresolved minor thread and newest full review. Reuse this feature item; issue #85 remains open but its existing fix and exact-head receipts are complete. Minimal change: unique disagreement peers keyed by recipe digest plus checkpoint, excluding the incumbent already supplied by the sealed evaluator. Extend the existing known-signal promotion regression and regenerate only the synthetic sanity receipt. Preserve cached completed receipts, real-data acceptance, thresholds, dependencies and disabled release approval. Registry CLI is 2026.10.18; pinned SDK stays 2026.10.13." + "2026-10-18T15:10:40.080Z",codex-agent,"The existing known-signal test now asserts exactly one incumbent entry and peer-count matrix [[1,2],[2,3]]. Deduplicate before environment.selection by recipe digest plus checkpoint, seeding the seen set with the incumbent. Revert proof: restore only runRlMeta previous peer collection with new assertions retained -> 0/1, actual generation-2 counts [3,4] versus expected [2,3]. Restored initial run passes 1/1. Regenerated synthetic receipt from the real test output; recursive comparison verifies all policies, scores, gains, bounds, promotions and final scores unchanged apart from unique diagnostics and fresh synthetic compartment identities. Real-data receipt unchanged; completed durable score receipts are adopted without migration. Total behavioral revert proofs now 25. Reuse existing linked test 5 rather than duplicate its command." + "2026-10-18T15:11:48.761Z",codex-agent,"Restored linked command node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts passes 2/2 through the pinned PM runner (20041 ms), including the duplicate-incumbent regression. Typecheck, build, test compilation, lint, zero duplication, docstrings (35 sources / 295 declarations), and changelog checks pass. Only peer collection changes in production. Full npm and Bun gates are pending on the next pushed head; no current-head full-gate success is claimed yet." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index eede0734..c46068f0 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -96,3 +96,7 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T14:29:06.664Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/52","value":{"created_at":"2026-10-18T14:29:06.664Z","author":"codex-agent","text":"Strengthened the mixed-alias concurrency regression: every contender uses an alias, so canonical persistence cannot pass because a canonical caller won. Independent behavioral proof restores only promoteGenerationCore raw approval persistence; the retained regression fails 0/1 with actual RL-APPROVAL versus expected rl-approval. Restoration passes the pinned linked alias command 2/2 (52006 ms). This is a second issue #85 proof and raises the total to 24. Production code remains exactly 5c9ab9a; the strengthened assertion will be included in the handoff commit and its full CI. Latest origin/main is already contained; canonical checkout is clean; private-path scan passes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:29:06.664Z"}],"before_hash":"9f539d3c19cd081adb6a38397441ab24de4603de4a0d9556cf5740766557960d","after_hash":"a98d6c4f44a2161f45cc0b6c9b4ea3cf697a52a6b76d0f06320693c9d8ed398f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"efa40a7dd9c88933cf8874f2800fd040e1af8eb1bc07b1ba132c540880e20c04"} {"hash_algorithm":"sha256","ts":"2026-10-18T14:35:03.715Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/53","value":{"created_at":"2026-10-18T14:35:03.715Z","author":"codex-agent","text":"Complete source gates on 5c9ab9a2a756bf626443b53f56127738ea85ef36: CI 39135240662 passes npm run release:check on Node 22 and 26 and bun run release:check on Node 26 with isolated HOME/global/system Git config. Each reports 628/628, 0 failures/cancellations/skips, 100% statements/lines/branches/functions, all 35 declared sources and 295 documented declarations. All logs verify the packaged sanity receipt, zero clones and production audit, changelog and identity checks. CodeQL 39135240660 passes. Revert proofs total 24; alias PM command 2/2, new four-findings command 4/4, direct isolated lineage 51/51; combined-harness setup failure remains explicit. Issue #85 is linked by Fixes in PR body and has a post-push evidence reply. Release stays disabled, no items closed, frozen live/sanity receipts unchanged. Handoff commit includes the stronger alias assertion and these receipts, then receives separate exact-head CI; no final independent review approval is claimed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:35:03.715Z"}],"before_hash":"a98d6c4f44a2161f45cc0b6c9b4ea3cf697a52a6b76d0f06320693c9d8ed398f","after_hash":"98b1b79a28bacc4f513da03595939a2a7866a0ef43261a00a848609a1564aeab","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"19c69818d34119c182a3e0f47a9531148f6fe9176e6cb444eb7ad2ef85f67a97"} {"hash_algorithm":"sha256","ts":"2026-10-18T14:35:06.415Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T14:35:06.415Z"}],"before_hash":"98b1b79a28bacc4f513da03595939a2a7866a0ef43261a00a848609a1564aeab","after_hash":"9377f59ad4975f1e92968806720423c9ceee99ab22a08eef4037d14e56e620f3","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"bb2e5009420eeaa39a2b724892248333acea3e3f993aed44ff56c998ea871b00"} +{"hash_algorithm":"sha256","ts":"2026-10-18T15:08:16.123Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:08:16.123Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"9377f59ad4975f1e92968806720423c9ceee99ab22a08eef4037d14e56e620f3","after_hash":"cdfee762e48ea49315d930ed22ab630f8a356e7f94a724fcd1cde665332891d5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"319497576c0a77981753cebb63fbeababde2f80922c5877adbf78ef818e681af"} +{"hash_algorithm":"sha256","ts":"2026-10-18T15:08:17.679Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/54","value":{"created_at":"2026-10-18T15:08:17.679Z","author":"codex-agent","text":"Review round on ef8210b: read the complete unresolved minor thread and newest full review. Reuse this feature item; issue #85 remains open but its existing fix and exact-head receipts are complete. Minimal change: unique disagreement peers keyed by recipe digest plus checkpoint, excluding the incumbent already supplied by the sealed evaluator. Extend the existing known-signal promotion regression and regenerate only the synthetic sanity receipt. Preserve cached completed receipts, real-data acceptance, thresholds, dependencies and disabled release approval. Registry CLI is 2026.10.18; pinned SDK stays 2026.10.13."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:08:17.679Z"}],"before_hash":"cdfee762e48ea49315d930ed22ab630f8a356e7f94a724fcd1cde665332891d5","after_hash":"ee22add3489bc79e95306718a869566a68bacef6fc559e5cfb70a7c66d1eccb9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a7b710df4dccb2d5fceb01f50838336de113c1c618419142d46bf329722507c2"} +{"hash_algorithm":"sha256","ts":"2026-10-18T15:10:40.080Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/55","value":{"created_at":"2026-10-18T15:10:40.080Z","author":"codex-agent","text":"The existing known-signal test now asserts exactly one incumbent entry and peer-count matrix [[1,2],[2,3]]. Deduplicate before environment.selection by recipe digest plus checkpoint, seeding the seen set with the incumbent. Revert proof: restore only runRlMeta previous peer collection with new assertions retained -> 0/1, actual generation-2 counts [3,4] versus expected [2,3]. Restored initial run passes 1/1. Regenerated synthetic receipt from the real test output; recursive comparison verifies all policies, scores, gains, bounds, promotions and final scores unchanged apart from unique diagnostics and fresh synthetic compartment identities. Real-data receipt unchanged; completed durable score receipts are adopted without migration. Total behavioral revert proofs now 25. Reuse existing linked test 5 rather than duplicate its command."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:10:40.080Z"}],"before_hash":"ee22add3489bc79e95306718a869566a68bacef6fc559e5cfb70a7c66d1eccb9","after_hash":"db49d85d3821048c1a90fe030fe9c4a658db0ade9cf4c115b63a2b475fca130c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"dbe499dda87cb88c90748a6e1131a2b10ab76442a7e1013e67e66098bb3328c7"} +{"hash_algorithm":"sha256","ts":"2026-10-18T15:11:48.761Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/56","value":{"created_at":"2026-10-18T15:11:48.761Z","author":"codex-agent","text":"Restored linked command node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts passes 2/2 through the pinned PM runner (20041 ms), including the duplicate-incumbent regression. Typecheck, build, test compilation, lint, zero duplication, docstrings (35 sources / 295 declarations), and changelog checks pass. Only peer collection changes in production. Full npm and Bun gates are pending on the next pushed head; no current-head full-gate success is claimed yet."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:11:48.761Z"}],"before_hash":"db49d85d3821048c1a90fe030fe9c4a658db0ade9cf4c115b63a2b475fca130c","after_hash":"a24252f7d995ba5e8a07c6a5ef2a38dbdd61bc55ab5fa0efde0ea954abe8b531","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"392ae1a4e60056e4a580f1d1993c50e99e8e7903c9597d29cfc04f61f9d36b76"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 996e8ebb..9a54b5c9 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -90,7 +90,7 @@ Adapters report structured progress and completion evidence over a documented st passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: 628/628 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared - budget, conditional promotion and resource-refusal regressions pass; twenty-four + budget, conditional promotion and resource-refusal regressions pass; twenty-five behaviour-only reverts fail with tests retained and restored code passes. The review round fixes canonical receipt identity, bounded programme ids and README command syntax; the physical OOM test waits for real daemon evidence @@ -113,7 +113,9 @@ Adapters report structured progress and completion evidence over a documented st and their behavior-only revert proofs. The alias persistence proof forces an alias caller to win; raw-ID persistence fails the retained assertion. Complete source verification passes 628/628 in all three release variants, and direct - isolated lineage acceptance passes 51/51. + isolated lineage acceptance passes 51/51. Disagreement peers are unique by + recipe digest and checkpoint; regenerated synthetic evidence preserves every + learning score and verdict. Completed historical receipts remain unchanged. ## Data boundary and capacity diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index 623cffbd..bf95774d 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -231,7 +231,7 @@ remain. Guard-only reverts for recipe lineage, public visibility, programme ids, retained reservation case folding and both resource fault injectors fail; restored implementations pass. PM-linked data/recipe, crash/promotion/budget, identity and resource-refusal commands pass 9/9, 3/3, 1/1 and 1/1 respectively. The expanded -review command passes 7/7. Twenty-four independent behavioral reverts fail across +review command passes 7/7. Twenty-five independent behavioral reverts fail across the feature and subsequent review rounds; restoring the implementations passes. A separate local full-suite attempt hit the unchanged 300-second HTTP crash-drill @@ -320,3 +320,13 @@ unsuitable combined link was removed. Both required complete release commands pass in isolated CI on the source head above. The assertion/documentation handoff commit receives a separate exact-head CI check; no final-head review approval, merge or release is implied. + +Disagreement diagnostics include each peer once by recipe digest and checkpoint, +with the incumbent supplied once by the evaluator. The known-signal regression +checks peer counts of `[1, 2]` and `[2, 3]` across its two generations. Restoring +only the previous peer collection fails that assertion with `[3, 4]` in generation +2. The regenerated synthetic receipt removes the duplicate incumbent rows; +policies, scores, confidence bounds, promotions and final-test results are +unchanged. Existing programmes adopt their completed score receipts without +rewriting historical diagnostics; new programmes produce the unique peer lists. +The real-data live receipt is unchanged. diff --git a/docs/meta-sanity-evidence.json b/docs/meta-sanity-evidence.json index 1745d000..5e0cf0cb 100644 --- a/docs/meta-sanity-evidence.json +++ b/docs/meta-sanity-evidence.json @@ -71,7 +71,7 @@ "score": { "mean": 0.5629, "samples": 10000, - "context": "db9287da5da16edda2be679e1fe67095489c8c395ca10799e6a4f7e06068c5ee" + "context": "ffc6fc59b23faae8aa3c27d2fc4523bb410c69aadad0aa3b34001ac968a7bf2c" }, "gain": 0.06859999999999994, "gain_lower_bound": 0.036740389785077876, @@ -165,7 +165,7 @@ "score": { "mean": 0.5265, "samples": 10000, - "context": "db9287da5da16edda2be679e1fe67095489c8c395ca10799e6a4f7e06068c5ee" + "context": "ffc6fc59b23faae8aa3c27d2fc4523bb410c69aadad0aa3b34001ac968a7bf2c" }, "gain": 0.03219999999999995, "gain_lower_bound": 0.0003403897850778881, @@ -268,7 +268,7 @@ "score": { "mean": 0.4943, "samples": 10000, - "context": "db9287da5da16edda2be679e1fe67095489c8c395ca10799e6a4f7e06068c5ee" + "context": "ffc6fc59b23faae8aa3c27d2fc4523bb410c69aadad0aa3b34001ac968a7bf2c" }, "gain": -0.06859999999999994, "gain_lower_bound": -0.100459610214922, @@ -292,12 +292,6 @@ } }, "disagreements": [ - { - "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", - "differing": 686, - "samples": 10000, - "rate": 0.0686 - }, { "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", "differing": 686, @@ -370,7 +364,7 @@ "score": { "mean": 0.4943, "samples": 10000, - "context": "db9287da5da16edda2be679e1fe67095489c8c395ca10799e6a4f7e06068c5ee" + "context": "ffc6fc59b23faae8aa3c27d2fc4523bb410c69aadad0aa3b34001ac968a7bf2c" }, "gain": -0.06859999999999994, "gain_lower_bound": -0.100459610214922, @@ -394,12 +388,6 @@ } }, "disagreements": [ - { - "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", - "differing": 686, - "samples": 10000, - "rate": 0.0686 - }, { "recipe": "sha256:30eccf433a17801ac6d91da530ae36a7ff47e2482534ab00538c4d16bd7ca512", "differing": 686, @@ -429,12 +417,12 @@ "before": { "mean": 0.5093, "samples": 10000, - "context": "7e0ba77a652c186c260bdf489aeaa0fadffaaf64a4849ec1ccf9505471359f66" + "context": "c21b10c9e338b51ccef33084da2e02514137c098274fe4a24ef40449d25514b4" }, "after": { "mean": 0.5806, "samples": 10000, - "context": "7e0ba77a652c186c260bdf489aeaa0fadffaaf64a4849ec1ccf9505471359f66" + "context": "c21b10c9e338b51ccef33084da2e02514137c098274fe4a24ef40449d25514b4" }, "diagnostics": { "majority_class": { diff --git a/meta.ts b/meta.ts index bb0360b3..caa9da3e 100644 --- a/meta.ts +++ b/meta.ts @@ -311,7 +311,10 @@ export async function runRlMeta(client: PmClient, coordinates: ProcessCoordinate const policy = await step(`m${generation}-c${index}`, { recipe: recipe.digest }, async () => await environment.fit(recipe, `${request.id}-m${generation}-c${index}`, signal) as unknown as JsonValue) as unknown as RecipePolicy; const comparison = await step(`m${generation}-score${index}`, { candidate: policy.checkpoint, incumbent: incumbent.recipe.digest }, async () => { - const { score, baseline, diagnostics } = environment.selection(policy, incumbent, [...generations.flatMap((previous) => previous.candidates), ...candidates].map((previous) => previous.candidate)); + const seen = new Set([`${incumbent.recipe.digest}:${incumbent.checkpoint}`]); + const peers = [...generations.flatMap((previous) => previous.candidates), ...candidates].map((previous) => previous.candidate) + .filter((peer) => { const key = `${peer.recipe.digest}:${peer.checkpoint}`; if (seen.has(key)) return false; seen.add(key); return true; }); + const { score, baseline, diagnostics } = environment.selection(policy, incumbent, peers); // Allocate family-wise error across all planned comparisons; search cannot relax the declared gate. const criterion = { ...config.criterion, confidence: 1 - (1 - config.criterion.confidence) / (config.meta_generations * config.candidates) }; return { ...compareRecipes(policy, incumbent, score, baseline, criterion), diagnostics } as unknown as JsonValue; diff --git a/test/meta.test.ts b/test/meta.test.ts index f1c6dcf9..ae33733b 100644 --- a/test/meta.test.ts +++ b/test/meta.test.ts @@ -441,6 +441,12 @@ test("a genuinely better recipe clears the unchanged gate and becomes the next m assert.ok(first.gain_lower_bound >= liveMetaConfiguration().criterion.effectThreshold); assert.equal(first.verdict.candidateEpsilon, Math.sqrt(Math.log(2 / (1 - 0.9875)) / (2 * splits["meta-validation"].count))); assert.ok(first.diagnostics.disagreements[0].rate > 0); + assert.deepEqual(report.generations.map((generation) => generation.candidates.map((candidate) => candidate.diagnostics.disagreements.length)), [[1, 2], [2, 3]]); + for (const generation of report.generations) { + for (const candidate of generation.candidates) { + assert.equal(candidate.diagnostics.disagreements.filter((peer) => peer.recipe === candidate.incumbent).length, 1, "the incumbent appears exactly once even after promotion"); + } + } assert.ok(report.final_test.after.mean > report.final_test.before.mean + liveMetaConfiguration().criterion.effectThreshold); assert.ok(report.final_test.after.mean > report.final_test.diagnostics.majority_class.mean); }); From 474c95c572e11078e9aa9751dad5c4101a486e58 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 17:27:12 +0200 Subject: [PATCH 23/24] docs: record verified peer diagnostic review evidence --- .agents/pm/features/pm-rl-meta.toon | 7 +++---- .agents/pm/history/pm-rl-meta.jsonl | 2 ++ RECURSIVE_TRAINING.md | 2 +- docs/meta-recursive.md | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.agents/pm/features/pm-rl-meta.toon b/.agents/pm/features/pm-rl-meta.toon index fe3e9fe5..84234e4d 100644 --- a/.agents/pm/features/pm-rl-meta.toon +++ b/.agents/pm/features/pm-rl-meta.toon @@ -6,13 +6,11 @@ status: in_progress priority: 2 tags: [] created_at: "2026-10-18T03:01:18.320Z" -updated_at: "2026-10-18T15:11:48.761Z" -assignee: codex-agent -claim_principal: codex-agent +updated_at: "2026-10-18T15:27:09.358Z" author: codex-agent acceptance_criteria: "Two bounded real-data meta-generations; seeded and optional decision-model proposals; recipe lineage, fail-closed promotion, no held-out leakage, idempotent reservation and resume; regression revert proofs and unchanged npm/Bun release gates." parent: pm-rl-apvf -comments[57]{created_at,author,text}: +comments[58]{created_at,author,text}: "2026-10-18T03:07:08.225Z",codex-agent,"Design: recipes bind declared learning-rate, inner generation/step, batch, data-selection, curriculum, temperature and reward-weight domains. The outer controller reuses existing leases and digested phase receipts; every inner fit uses the packaged process trainer and the same approved atomic resource reservations. Separate repository roles supply training, meta-validation and untouched final-test data; training-repository items are further split for inner held-out evaluation. Only sanitized lifecycle-state prefixes leave committed public MIT histories. Statistical recipe selection uses exact-match meta-validation evidence with distinct-example counts and a comparison-wise confidence allocation; proxy rewards cannot authorize recipe promotion. Conservative search reservations are held once across resume. No release enablement or dependency pin change." "2026-10-18T03:24:16.558Z",codex-agent,"Initial numerical and public-dataset regressions passed 8/8. Real-data acceptance caught and corrected the installed GitHub CLI license metadata contract (MIT is licenseInfo.key=mit); public visibility and public commit checks remain mandatory. The optional proposer now persists a pre-request intent: completed results replay; an unresolved response falls back to the seeded recipes without making another physical request. The search domain is deliberately small (at most two inner steps and 256 samples per batch), and reservations derive their worst-case charge from the declared recipe domains. Shared-host deadline failures are retained; no existing acceptance timeout or coverage threshold was relaxed." "2026-10-18T03:31:31.203Z",codex-agent,"Behavioural revert proof in an isolated source snapshot: remove only the recipe field from generationTrainingConfig, retain all tests, and run node --test test/recipe.test.ts. Result: 2/3 pass, the lineage regression fails because its stored recipe digest is undefined; restored function passes 3/3. Separately remove only the public-visibility conjunct from the dataset source guard and run node --test --test-name-pattern=\"builder fails before\" test/dataset.test.ts: 0/1 pass, Missing expected exception for PRIVATE metadata. The restored package retains the guard. No thresholds, legacy code paths or dependency pins changed. Both tests import TypeScript sources directly, so no dist rebuild is needed for these proofs." @@ -70,6 +68,7 @@ comments[57]{created_at,author,text}: "2026-10-18T15:08:17.679Z",codex-agent,"Review round on ef8210b: read the complete unresolved minor thread and newest full review. Reuse this feature item; issue #85 remains open but its existing fix and exact-head receipts are complete. Minimal change: unique disagreement peers keyed by recipe digest plus checkpoint, excluding the incumbent already supplied by the sealed evaluator. Extend the existing known-signal promotion regression and regenerate only the synthetic sanity receipt. Preserve cached completed receipts, real-data acceptance, thresholds, dependencies and disabled release approval. Registry CLI is 2026.10.18; pinned SDK stays 2026.10.13." "2026-10-18T15:10:40.080Z",codex-agent,"The existing known-signal test now asserts exactly one incumbent entry and peer-count matrix [[1,2],[2,3]]. Deduplicate before environment.selection by recipe digest plus checkpoint, seeding the seen set with the incumbent. Revert proof: restore only runRlMeta previous peer collection with new assertions retained -> 0/1, actual generation-2 counts [3,4] versus expected [2,3]. Restored initial run passes 1/1. Regenerated synthetic receipt from the real test output; recursive comparison verifies all policies, scores, gains, bounds, promotions and final scores unchanged apart from unique diagnostics and fresh synthetic compartment identities. Real-data receipt unchanged; completed durable score receipts are adopted without migration. Total behavioral revert proofs now 25. Reuse existing linked test 5 rather than duplicate its command." "2026-10-18T15:11:48.761Z",codex-agent,"Restored linked command node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts passes 2/2 through the pinned PM runner (20041 ms), including the duplicate-incumbent regression. Typecheck, build, test compilation, lint, zero duplication, docstrings (35 sources / 295 declarations), and changelog checks pass. Only peer collection changes in production. Full npm and Bun gates are pending on the next pushed head; no current-head full-gate success is claimed yet." + "2026-10-18T15:27:08.610Z",codex-agent,"Complete peer-dedup source verification on 29193adc638a40b04c945e657eaaadfa034a2371: CI 39139389795 passes npm run release:check on Node 22/26 and bun run release:check on Node 26 with isolated HOME and global/system Git config. Each reports 628/628, zero failures/cancellations/skips, 100% statements/lines/branches/functions, all 35 sources and 295 documented declarations. CodeQL 39139389823 passes. The linked baseline/known-signal command passes 2/2; fix-only peer-collection revert fails 0/1 with [3,4] instead of [2,3]. Total proofs 25. Regenerated synthetic receipt changes only duplicate rows and fresh synthetic contexts; all learning scores/verdicts and the real-data receipt are unchanged. CodeRabbit inspected source and receipt, explicitly did not execute tests, and resolved its own thread. Reply was posted after push; no author resolution/merge/release. Fresh-clone strict health passes with three existing advisories, private-path scan passes, latest main is contained, and dependency pins/thresholds remain unchanged. Handoff metadata commit receives its own exact-head CI." files[24]{path,scope}: .github/workflows/ci.yml,project dataset.ts,project diff --git a/.agents/pm/history/pm-rl-meta.jsonl b/.agents/pm/history/pm-rl-meta.jsonl index c46068f0..431e4a04 100644 --- a/.agents/pm/history/pm-rl-meta.jsonl +++ b/.agents/pm/history/pm-rl-meta.jsonl @@ -100,3 +100,5 @@ {"hash_algorithm":"sha256","ts":"2026-10-18T15:08:17.679Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/54","value":{"created_at":"2026-10-18T15:08:17.679Z","author":"codex-agent","text":"Review round on ef8210b: read the complete unresolved minor thread and newest full review. Reuse this feature item; issue #85 remains open but its existing fix and exact-head receipts are complete. Minimal change: unique disagreement peers keyed by recipe digest plus checkpoint, excluding the incumbent already supplied by the sealed evaluator. Extend the existing known-signal promotion regression and regenerate only the synthetic sanity receipt. Preserve cached completed receipts, real-data acceptance, thresholds, dependencies and disabled release approval. Registry CLI is 2026.10.18; pinned SDK stays 2026.10.13."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:08:17.679Z"}],"before_hash":"cdfee762e48ea49315d930ed22ab630f8a356e7f94a724fcd1cde665332891d5","after_hash":"ee22add3489bc79e95306718a869566a68bacef6fc559e5cfb70a7c66d1eccb9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a7b710df4dccb2d5fceb01f50838336de113c1c618419142d46bf329722507c2"} {"hash_algorithm":"sha256","ts":"2026-10-18T15:10:40.080Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/55","value":{"created_at":"2026-10-18T15:10:40.080Z","author":"codex-agent","text":"The existing known-signal test now asserts exactly one incumbent entry and peer-count matrix [[1,2],[2,3]]. Deduplicate before environment.selection by recipe digest plus checkpoint, seeding the seen set with the incumbent. Revert proof: restore only runRlMeta previous peer collection with new assertions retained -> 0/1, actual generation-2 counts [3,4] versus expected [2,3]. Restored initial run passes 1/1. Regenerated synthetic receipt from the real test output; recursive comparison verifies all policies, scores, gains, bounds, promotions and final scores unchanged apart from unique diagnostics and fresh synthetic compartment identities. Real-data receipt unchanged; completed durable score receipts are adopted without migration. Total behavioral revert proofs now 25. Reuse existing linked test 5 rather than duplicate its command."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:10:40.080Z"}],"before_hash":"ee22add3489bc79e95306718a869566a68bacef6fc559e5cfb70a7c66d1eccb9","after_hash":"db49d85d3821048c1a90fe030fe9c4a658db0ade9cf4c115b63a2b475fca130c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"dbe499dda87cb88c90748a6e1131a2b10ab76442a7e1013e67e66098bb3328c7"} {"hash_algorithm":"sha256","ts":"2026-10-18T15:11:48.761Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/56","value":{"created_at":"2026-10-18T15:11:48.761Z","author":"codex-agent","text":"Restored linked command node --test --test-name-pattern=\"synthetic held-out|genuinely better\" test/meta.test.ts passes 2/2 through the pinned PM runner (20041 ms), including the duplicate-incumbent regression. Typecheck, build, test compilation, lint, zero duplication, docstrings (35 sources / 295 declarations), and changelog checks pass. Only peer collection changes in production. Full npm and Bun gates are pending on the next pushed head; no current-head full-gate success is claimed yet."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:11:48.761Z"}],"before_hash":"db49d85d3821048c1a90fe030fe9c4a658db0ade9cf4c115b63a2b475fca130c","after_hash":"a24252f7d995ba5e8a07c6a5ef2a38dbdd61bc55ab5fa0efde0ea954abe8b531","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"392ae1a4e60056e4a580f1d1993c50e99e8e7903c9597d29cfc04f61f9d36b76"} +{"hash_algorithm":"sha256","ts":"2026-10-18T15:27:08.610Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/57","value":{"created_at":"2026-10-18T15:27:08.610Z","author":"codex-agent","text":"Complete peer-dedup source verification on 29193adc638a40b04c945e657eaaadfa034a2371: CI 39139389795 passes npm run release:check on Node 22/26 and bun run release:check on Node 26 with isolated HOME and global/system Git config. Each reports 628/628, zero failures/cancellations/skips, 100% statements/lines/branches/functions, all 35 sources and 295 documented declarations. CodeQL 39139389823 passes. The linked baseline/known-signal command passes 2/2; fix-only peer-collection revert fails 0/1 with [3,4] instead of [2,3]. Total proofs 25. Regenerated synthetic receipt changes only duplicate rows and fresh synthetic contexts; all learning scores/verdicts and the real-data receipt are unchanged. CodeRabbit inspected source and receipt, explicitly did not execute tests, and resolved its own thread. Reply was posted after push; no author resolution/merge/release. Fresh-clone strict health passes with three existing advisories, private-path scan passes, latest main is contained, and dependency pins/thresholds remain unchanged. Handoff metadata commit receives its own exact-head CI."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:27:08.610Z"}],"before_hash":"a24252f7d995ba5e8a07c6a5ef2a38dbdd61bc55ab5fa0efde0ea954abe8b531","after_hash":"4d8746d3fe459c771c71810baa157127020d2f5ee901b61bff1c92df4dafa297","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"fd31d2e2b74a34edbb3a3580c8b5bbd26598222a14f4539b19264daf793be5bc"} +{"hash_algorithm":"sha256","ts":"2026-10-18T15:27:09.358Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7037d132570a6285e78b5af5","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]},"topic":{"value":"pm-rl-meta","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-rl-meta","lineage:pm-rl-meta","lineage:pm-rl-apvf"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T15:27:09.358Z"}],"before_hash":"4d8746d3fe459c771c71810baa157127020d2f5ee901b61bff1c92df4dafa297","after_hash":"4cd1e7affd803b63deddee39c7d36fb7aa47ad1c870339626224fb6c8826918a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"7f229b1e7e150b749d720e97580b88440350be9b7eeb0c49651e95dc3b6463d5"} diff --git a/RECURSIVE_TRAINING.md b/RECURSIVE_TRAINING.md index 9a54b5c9..53d9711d 100644 --- a/RECURSIVE_TRAINING.md +++ b/RECURSIVE_TRAINING.md @@ -86,7 +86,7 @@ Adapters report structured progress and completion evidence over a documented st 0.95-confidence, ten-sample, 0.01-effect gate: gain 0.0686, lower bound 0.036740389785077876, and final-test 5093/10000 to 5806/10000. This is a sanity result, not real-tracker improvement. No gate or real feature was weakened. - [Complete source verification](https://github.com/unbraind/pm-rl/actions/runs/39135240662) + [Complete source verification](https://github.com/unbraind/pm-rl/actions/runs/39139389795) passes the exact npm command on Node 22 and 26 and the Bun command on Node 26: 628/628 each, zero failures/skips, all four coverage metrics 100% across all 35 declared sources and 295 documented declarations. Physical crash, shared diff --git a/docs/meta-recursive.md b/docs/meta-recursive.md index bf95774d..8207cccc 100644 --- a/docs/meta-recursive.md +++ b/docs/meta-recursive.md @@ -209,8 +209,8 @@ predictions, and full disagreement. ## Release verification -The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39135240662) -on `5c9ab9a2a756bf626443b53f56127738ea85ef36` +The [source-verification CI run](https://github.com/unbraind/pm-rl/actions/runs/39139389795) +on `29193adc638a40b04c945e657eaaadfa034a2371` executes `npm run release:check` on Node 22 and 26 and `bun run release:check` on Node 26 with isolated HOME and global/system Git configuration. Each passes 628/628 tests, zero failures/skips, 100% statements/lines/branches/functions over From cf6bdcf34540d47199d15cc98969b991aeec29cf Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 18 Oct 2026 18:11:48 +0200 Subject: [PATCH 24/24] Build the inner held-out id set once instead of once per training example The overlap guard rebuilt a Set of every evaluation id for each training example, O(|train| x |held-out|) allocations at up to 10,000 examples per split. Behaviour is unchanged: meta tests 28/28, typecheck and lint pass. --- tracker-environment.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tracker-environment.ts b/tracker-environment.ts index 77ea7704..e4d81642 100644 --- a/tracker-environment.ts +++ b/tracker-environment.ts @@ -95,7 +95,8 @@ export function trackerDiagnostics(examples: readonly TrackerExample[], policy: async function fitRecipe(client: PmClient, coordinates: ProcessCoordinates, request: Pick, manifest: TrackerDataset, recipe: Recipe, id: string, signal: AbortSignal): Promise { const training = recipeExamples(readTrackerSplit(request.dataset, manifest, "train"), recipe, true); const evaluation = recipeExamples(readTrackerSplit(request.dataset, manifest, "inner-held-out"), recipe, false); - assert.ok(!training.some((example) => new Set(evaluation.map((held) => held.id)).has(example.id)), "meta_inner_overlap"); + const heldOutIds = new Set(evaluation.map((held) => held.id)); + assert.ok(!training.some((example) => heldOutIds.has(example.id)), "meta_inner_overlap"); const config = request.config; const report = await runRlLoop(client, coordinates, { id, approval: request.approval, signal, config: { recipe: recipe as unknown as JsonValue, environment: { name: "Public tracker terminal disposition", version: manifest.digest },