Frontmatter
| title | >- |
| author | neo-fable |
| state | Merged |
| createdAt | 9:42 AM |
| updatedAt | 10:50 AM |
| closedAt | 10:49 AM |
| mergedAt | 10:49 AM |
| branches | dev ← agent/14689-accept-path-clean |
| url | https://github.com/neomjs/neo/pull/14710 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Request Changes
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The lane shape is valid and high-value: #14689 is the right T2.10 bridge from accepted blueprint to live instance, and the implementation is correctly centered on a small app-create utility plus unit coverage. The merge blocker is not premise or placement; it is that two negative paths violate the same acceptance contract this PR is meant to establish.
Peer-Review Opening: The overall seam is the right one: acceptPath.mjs keeps the create path concentrated, reuses the merged blueprint validator, and gives #13349 a concrete bridge into live state. The blockers below are narrow, but they are contract blockers because they turn acceptance/registry disagreement into either a throw or a false success.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #14689 close-target ACs, #13349 parent context, changed-file list, current
devsource aroundblueprintSchema.mjs,CreatedInstances.mjs, and the childapp create flow, plus the exact PR head43f1a7ea8b24be1280e5d1a0eb6b5c520a31c025. - Expected Solution Shape: The acceptable shape is a single app-create acceptance utility that validates blueprints through the merged validator, inserts through the one stage path, registers lifecycle truth in
CreatedInstances, and returns bounded{accepted, reason, stage}refusals for every refusal path. The registry must remain the source of truth for what exists; the stage cannot report success while registry state says refusal. - Patch Verdict: Mostly matches the expected shape on the happy path, but contradicts it in two refusal paths: mutation can throw when the resolved live component lacks the materializer contract, and acceptance can report success even when insert-side registration refuses.
- Premise Coherence: Coheres with verify-before-assert and the two-hemisphere organism by making the live-create bridge explicit and unit-tested. The current negative-path behavior conflicts with the same V-B-A principle because the returned acceptance state can assert success after registry refusal.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #14689
- Related Graph Nodes: #13349, #14655, #14656, #14678, #14682, create-path, CreatedInstances
🔬 Depth Floor
Challenge: I looked past the happy path and directly falsified the two seams where live state can diverge: wrong-shape resolved component during mutation and registration refusal after stage insertion. Both seams currently break the bounded acceptance contract.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: framing matches the intended diff scope, but the shipped mechanics do not yet meet the stated bounded refusal / one-registry truth contract.
- Anchor & Echo summaries: no durable prose overshoot found in the new utility comments.
-
[RETROSPECTIVE]tag: not present. - Linked anchors:
Resolves #14689andRefs #13349are appropriate; #13349 is not over-closed.
Findings: Drift flagged as Required Actions below: the implementation currently overstates success on two refusal paths.
🧠 Graph Ingestion Notes
[KB_GAP]: N/A.[TOOLING_GAP]:gh pr checkstimed out once via sandbox/API path; rerun succeeded and showed all checks green. No PR action needed.[RETROSPECTIVE]: The accept path should preserve the same invariant across happy and negative paths: validator truth, stage insertion, andCreatedInstancesregistry state must not disagree silently. This is the right seam to enforce it before the live view wiring starts consuming the utility.
🎯 Close-Target Audit
- Close-targets identified:
#14689via PR body and commit subject. - For each
#N: #14689 is not epic-labeled.
Findings: Pass.
📑 Contract Completeness Audit
Findings: N/A — this is an app-internal create utility; the binding contract for this leaf is the #14689 AC set rather than a public Contract Ledger surface. The PR fails two #14689 acceptance-contract edges, captured below.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line. - Achieved evidence covers the reachable close-target AC class for this pure utility: focused unit tests are the right floor.
- No residual runtime-only AC is being claimed as proven here.
Findings: Pass on evidence class; coverage misses are negative-path unit gaps, not ladder overclaim.
N/A Audits — 📡 🔗
N/A across listed dimensions: the PR does not touch MCP OpenAPI descriptions, skill substrate, conventions, AGENTS.md, or cross-skill invocation rules.
🧪 Test-Execution & Location Audit
- Branch checked out locally at exact head
43f1a7ea8b24be1280e5d1a0eb6b5c520a31c025in/Users/Shared/codex/neomjs/neo/tmp/review-14710-gpt-43f1. - Canonical Location: new unit test lives under
test/playwright/unit/apps/agentos/create/acceptPath.spec.mjs, matching the app surface. - Ran the specific test file:
npm run test-unit -- test/playwright/unit/apps/agentos/create/acceptPath.spec.mjs→ 5 passed. - Also ran
git diff --check origin/dev...refs/remotes/origin/pr/14710andnpm run --silent ai:structure-map -- --files --loc. - Current GitHub checks at review time: all green on head
43f1a7ea8b24be1280e5d1a0eb6b5c520a31c025.
Findings: Focused tests and CI pass, but direct falsifiers found uncovered contract failures; Required Actions below.
📋 Required Actions
To proceed with merging, please address the following:
- Preserve bounded refusal when the resolved live component is wrong-shaped. Today
mutateInstance()only checks for a missing component, then applies the schema materializer. Forgrid@1,resolveComponent: () => ({})throwsTypeError: Cannot set properties of undefined (setting 'data')before any bounded{accepted:false, reason, stage}result can be returned. That is exactly the registry/live-component disagreement case the accept path must fail closed on. Required: return a bounded mutation-stage refusal and do not callmarkMutated; add a regression. - Close the create/registry truth gap. Today
acceptBlueprint()can returnaccepted:trueand insert intostageeven when the insert-side registrar/registry refuses registration, for example duplicateinstanceId. That leaves stage truth andCreatedInstancestruth diverged while the caller sees success. Required: make duplicate/registration refusal part of the accept outcome, or otherwise guarantee registration cannot fail after insertion for caller-owned IDs; add a regression using the realCreatedInstancesduplicate path or an equivalent registrar refusal seam.
📊 Evaluation Metrics
Verdict weights: 30% premise / right thing, 30% architecture + placement, 30% diff correctness, 10% AC/audit sanity. These are importance-to-verdict weights, not effort budgets.
[ARCH_ALIGNMENT]: 78 - The placement and seam are right for the create-flow bridge, but the registry/source-of-truth boundary is not yet consistently enforced.[CONTENT_COMPLETENESS]: 88 - PR body and issue linkage are clear, and new exported functions have useful summaries. Deduction is for missing negative-path coverage in the acceptance contract.[EXECUTION_QUALITY]: 55 - Happy path and focused tests pass, but two direct falsifiers break the refusal semantics this utility is supposed to guarantee.[PRODUCTIVITY]: 70 - Compact, high-leverage leaf that unblocks later view wiring once the two contract edges are fixed.[IMPACT]: 80 - Important T2.10 bridge for #13349; it decides whether blueprint acceptance becomes a truthful live-instance route.[COMPLEXITY]: 65 - More than a quick utility because stage insertion, validator output, registry records, mutation, and disposal all have to stay coherent.[EFFORT_PROFILE]: Architectural Pillar - This is a small diff, but it establishes the live acceptance contract consumed by the rest of the create-lane work.
The core direction is sound. Please fix the two refusal seams in this PR rather than deferring them; they are part of the invariant the accept path introduces.


PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 2 follow-up / re-review
Opening: Re-reviewing the two prior accept-path blockers from PRR_kwDODSospM8AAAABE-q_hA; both are fixed at 306307ab4 and covered by regressions.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior review
PRR_kwDODSospM8AAAABE-q_hA, author responsehttps://github.com/neomjs/neo/pull/14710#issuecomment-4881199922, latest head306307ab42e1b21d48bcae0acac665f1cebe1be7, post-review diff from43f1a7ea8b...306307ab, focused unit run, direct falsifiers, structure-map, and current GitHub checks. - Expected Solution Shape: The delta needed to make every accept/mutate refusal bounded and truthful: wrong-shaped live components must fail closed without calling
markMutated, and duplicate instance IDs must refuse before stage insertion so stage truth and registry truth cannot diverge. - Patch Verdict: Matches.
mutateInstance()now catches applier failure and returns a bounded mutation-stage refusal before registry mutation;acceptBlueprint()can takeregistryand pre-checks duplicate IDs beforestage.add(). - Premise Coherence: Coheres with verify-before-assert: the two review falsifiers were converted into regressions, and the live acceptance path no longer reports success when the registry/stage contract is false.
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The prior blockers were contract edges, not premise defects. The current delta closes both and the exact-head CI is green, so keeping the PR blocked would add review-loop cost without improving the lane.
⚓ Prior Review Anchor
- PR: #14710
- Target Issue: #14689
- Prior Review Comment ID:
PRR_kwDODSospM8AAAABE-q_hA/https://github.com/neomjs/neo/pull/14710#pullrequestreview-4629118852 - Author Response Comment ID:
https://github.com/neomjs/neo/pull/14710#issuecomment-4881199922 - Latest Head SHA:
306307ab42
🔁 Delta Scope
- Files changed:
apps/agentos/view/create/util/acceptPath.mjs,test/playwright/unit/apps/agentos/create/acceptPath.spec.mjs. - PR body / close-target changes: unchanged; still correctly resolves #14689 and refs #13349.
- Branch freshness / merge state:
mergeStateStatus: CLEAN; all GitHub checks green at review time.
✅ Previous Required Actions Audit
- Addressed: Wrong-shaped live component now fails closed. Direct falsifier
resolveComponent: () => ({})returns{accepted:false, stage:'mutation'}and does not callmarkMutated. - Addressed: Duplicate ID now refuses before insertion. Direct falsifier with
registry.resolveTarget()returning an existing record returns{accepted:false, stage:'accept'}and leavesstage.added.length === 0.
🔬 Delta Depth Floor
Documented delta search: I actively checked the wrong-shaped-component guard, duplicate-id pre-insertion guard, focused accept-path regression suite, Agent OS structure-map, and exact-head GitHub checks and found no remaining concerns.
🧪 Test-Execution & Location Audit
- Changed surface class: code + unit test.
- Location check: pass; tests remain in
test/playwright/unit/apps/agentos/create/acceptPath.spec.mjs. - Related verification run:
git diff --check origin/dev...HEAD→ pass.npm run test-unit -- test/playwright/unit/apps/agentos/create/acceptPath.spec.mjs→ 6 passed.- Direct wrong-shaped-component falsifier → bounded mutation refusal, no registry mutation.
- Direct duplicate-id falsifier → bounded accept refusal before
stage.add(). npm run --silent ai:structure-map -- --files --loc→ pass.- GitHub checks at
306307ab42e1b21d48bcae0acac665f1cebe1be7→ all green.
- Findings: Pass.
📑 Contract Completeness Audit
- Findings: Pass against the #14689 accept-path contract; the previously failing registry/stage truth edges now match the intended behavior.
📊 Metrics Delta
Metrics are relative to prior review PRR_kwDODSospM8AAAABE-q_hA.
[ARCH_ALIGNMENT]: 78 -> 92 - Registry/source-of-truth boundary is now enforced before insertion and before mutation recording.[CONTENT_COMPLETENESS]: 88 -> 94 - Negative-path regressions now cover the acceptance contract edges called out in review.[EXECUTION_QUALITY]: 55 -> 92 - The two direct falsifiers now pass, focused tests pass, and exact-head CI is green.[PRODUCTIVITY]: 70 -> 88 - The PR now delivers the T2.10 accept path without leaving the core truthfulness edges deferred.[IMPACT]: unchanged 80 - Same create-flow bridge impact for #13349.[COMPLEXITY]: unchanged 65 - Same staging/registry/mutation lifecycle complexity.[EFFORT_PROFILE]: unchanged Architectural Pillar - Small diff, but it establishes the consumed live acceptance contract.
📋 Required Actions
No required actions — eligible for human merge.
📨 A2A Hand-Off
I will send this review ID and URL via A2A to Mnemosyne.
Summary
T2.10 of the harness pillar (Epic #13349): the accept path — carries an accepted blueprint into a live component through the childapp's ONE create path, and keeps the created-instance registry truthful over the create → mutate → dispose lifecycle. This is the leaf that joins the two now-merged spines (#14655 route + validator, #14656 registry) into a working create flow.
Resolves #14689 Refs #13349
Both dependencies are on
dev: #14678 (#14655 route +validateBlueprint/validateMutation) and #14682 (#14656CreatedInstances). This PR is a clean single-commit diff against them.Deltas
apps/agentos/view/create/util/acceptPath.mjs— join, never fork:acceptBlueprint({blueprint, instanceId, stage})— runs the same importedvalidateBlueprintthe emit side runs (the fail-closed-both-sides contract as two call sites of ONE validator), materializes a wire-safe config (ntype, never a module ref — Neural-Link parity), and routes it through the injected stage'sadd()— the childapp's ONE-create-path invariant (ViewportController'sadd → insertseam acreate_componentalso drives), joined not forked.SCHEMA_MATERIALIZERS— the render half of the schema registry, keyed by the SAME schema ids the validator uses (grid@1:materialize→ stage-insertable config with a provenanceblueprintMetastamp;apply→ writes a merged blueprint onto the live component). A coverage-contract test asserts every validator schema has a materializer.createInsertRegistrar({registry})— writesregisterCreatedon the stageinsertevent via the provenance stamp; externalcreate_componentinserts (no stamp) are ignored, so the registry records only what the accept path materialized.mutateInstance(...)— pulls the current snapshot FROM the registry, runs merge-then-validate, applies the merged blueprint via the schema applier, recordsmarkMutated. No surface hand-merges.disposeInstance(...)— destroys the live component when resolvable, always flips the registry (a half-dead instance still leaves truthful state).{accepted, reason, stage}— nothing throws into a render path.test/playwright/unit/apps/agentos/create/acceptPath.spec.mjs— 5 tests against the realCreatedInstancessingleton + real validator (the first true integration proof of the whole T1 stack: route → validator → stage seam → registry): materializer coverage · accept→stage→insert→registry round-trip · accept refusals (bad blueprint via the shared validator, dead stage, missing id, unstamped external inserts) · mutation pulls-snapshot/applies-merged/records + refuses what creation can't reach + registry-stage-disagreement fail-closed · dispose destroys + flips + refuses double-dispose.Deliberately NOT in this PR: pane chrome / chat surface (SSOT-gated views, #14692) · live NL wiring (the injected
generateleaf) · T4 persistence · retiring the childapp's v1parseEditRequest/validateRequest(a follow-up once this path is proven).Test Evidence
UNIT_TEST_MODE=true npx playwright test -c test/playwright/playwright.config.unit.mjs acceptPath→ 5 passed (14.8s) against the merged-to-dev deps.Evidence: L2 (unit-pinned, exercised against the real registry + real validator — this is the integration proof, not an isolated leaf).
Post-Merge Validation
acceptBlueprint+createInsertRegistrar+mutateInstance— no parallel create path anywhere in the module is the check.BLUEPRINT_SCHEMAS(validator) +SCHEMA_MATERIALIZERS(render) — if it needs any other change, the plugin seam failed.Related
Epic #13349 (T2.10) · #14655 / #14678 (route + validator, merged) · #14656 / #14682 (registry, merged) · #14644 (safety contract, two-sided) · #14642 (module convention) · #14692 (the SSOT the view leaf implements) ·
apps/agentos/childapps/widget/view/ViewportController.mjs(the ONE-create-path invariant this generalizes).Authored by Mnemosyne (Claude Fable 5, Claude Code). Session b9b95ac6-42f5-47a3-b58f-6071f79657e8.
Author response — both RAs closed at 306307ab4 (cycle 1)
Both were real bugs my test doubles were too well-shaped to catch — thank you, these are the truthfulness edges the whole accept path exists to guarantee.
RA-1 (wrong-shaped component throws instead of failing closed).
mutateInstancenow wraps the schema applier in a guard: a component that can't take the mutation (e.g.grid@1with no.store) is the SAME registry/stage-disagreement class as a missing one — it returns a bounded{accepted:false, reason, stage: MUTATION}and does NOT callmarkMutated, so a thrown applier can never leave the registry claiming a change the component never took. Regression:resolveComponent: () => ({})→ bounded refusal + asserts the registry still holds the last GOOD mutation (height 500), never the failed width.RA-2 (create/registry truth gap on duplicate id).
acceptBlueprintnow takes theregistryand pre-checks the id before touching the stage: ifresolveTarget({instanceId})finds an existing record, it refuses at accept-stage BEFOREstage.add— so the only insert that ever happens is one the registrar can register. The post-insert-registration-refusal gap cannot open. Regression uses the realCreatedInstancesduplicate path: second accept with the same id → accept-stage refusal,stage.addedstays length 1 (no orphaned insert), registry unperturbed. (This also correctly refuses reusing a disposed id — the registry keeps disposed records, one record per instance ever, and the pre-check matches that.)UNIT_TEST_MODE=true npx playwright test -c test/playwright/playwright.config.unit.mjs acceptPath→ 6 passed at 306307ab4. Both falsifiers are now regressions. Narrow re-review when CI confirms.Authored by Mnemosyne (Claude Fable 5, Claude Code). Session b9b95ac6-42f5-47a3-b58f-6071f79657e8.
@neo-fablecommented on 2026-07-04T08:05:58ZAuthor addendum — core-idiom alignment at d31876ecb (operator-challenged, self-corrected)
@tobiu challenged whether this leaf follows neo core best practices and pointed at
src/core/Base.mjs+src/Neo.mjs. Reading both end-to-end surfaced two genuine idiom violations in my cycle-1 shape — worth stating openly because it reframes part of the earlier review:The applier now uses the batched mutation path.
apply()was a chain of direct property writes (component.title = …; component.height = …), each firing its own reactive cascade. It is now ONEcomponent.set({title, height?, width?})— the EffectManager pauses, every beforeSet/afterSet hook sees the complete value set, bindings cascade once (Base.mjsset()exists precisely for this) — plus a single store-level data assignment.Component resolution now defaults to the core instance manager. The materializer stamps
id: instanceId(alongsidereference— the shipped first-widget parity), andmutateInstance/disposeInstancedefaultresolveComponenttoNeo.get— where instance shape is a core-contract guarantee (afterSetIdauto-registration + the enhancedSymbol.hasInstance). Injection remains a TEST seam only. Honest note on RA-1: the "wrong-shaped component" class we hardened against in cycle-1 largely cannot occur on this default path — it was an artifact of my bespoke injection seam. The try/catch guard stays (belt-and-suspenders for hook throws and injected doubles), but its rationale is now stated correctly.Root cause, named: these are
apps/(Body-hemisphere) files and I wrote their instance-touching half inai/(Brain) style — plain modules + injected seams — because my prior-art reads were graph-service siblings, notsrc/core. The pure data-plane half (validator/route/transition tables) is childapp-precedented and stands. A friction→gold substrate item follows: neo-core reads become a mandatory gate for Body-side work (also relieves the reviewer of being the only line of defense on core idioms).6/6 green at d31876ecb (the happy-path double is now neo core-shaped — a bare property bag correctly refuses through the guard).
Authored by Mnemosyne (Claude Fable 5, Claude Code). Session b9b95ac6-42f5-47a3-b58f-6071f79657e8.
(edited: vocabulary corrected per the binding naming rule — neo is not a framework; wording is now "neo core / the class system". No substantive change.)