Exercise feature activation rollback and old-session artifact retention

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9
This commit is contained in:
tegwick 2026-09-26 23:14:34 +02:00
parent b8eec87f08
commit e34ec3fafe
22 changed files with 1661 additions and 1 deletions

13
TREE.md
View file

@ -368,6 +368,18 @@ research/experiments/boundary-recovery/routing-fixture.jsx
research/experiments/boundary-recovery/routing-results.json
research/experiments/boundary-recovery/routing-transform.mjs
research/experiments/boundary-recovery/routing.mjs
research/experiments/feature-release/README.md
research/experiments/feature-release/account-a1.js
research/experiments/feature-release/experiment.mjs
research/experiments/feature-release/host.js
research/experiments/feature-release/package-lock.json
research/experiments/feature-release/package.json
research/experiments/feature-release/provenance.json
research/experiments/feature-release/reports-r1.js
research/experiments/feature-release/reports-r2.js
research/experiments/feature-release/reports-r3.js
research/experiments/feature-release/result.json
research/experiments/feature-release/shared.js
research/experiments/matrix-recovery/README.md
research/experiments/matrix-recovery/experiment.mjs
research/experiments/matrix-recovery/package-lock.json
@ -383,6 +395,7 @@ research/reviews/BoundaryRecoveryExperiment.md
research/reviews/CarniatoAdmissionRegression.json
research/reviews/FeatureDeploymentBoundaries.md
research/reviews/FeatureDeploymentSources.json
research/reviews/FeatureReleaseExperiment.md
research/reviews/FrontendRecoveryImplementations.md
research/reviews/FrontendRecoverySources.json
research/reviews/JoplinConflictScreen.json

View file

@ -65,3 +65,7 @@ Latest breadth evidence: [feature versus deployment boundaries](reviews/FeatureD
compares pinned example sources and adds [provisional VC-06](walkthroughs/VC06-MicrofrontendEstate.md).
Independent Feature Boundary develops an existing seed; current corpus has seventeen
hypotheses and four synthetic walkthroughs. No deployment independence was runtime-verified.
Latest execution: [feature release lifecycle](reviews/FeatureReleaseExperiment.md)
records 14/14 expected observations across two browsers. It distinguishes fresh,
already-loaded and delayed-load sessions, and includes negative failure controls.

View file

@ -47,4 +47,15 @@ the other. Boundaries can coincide without becoming the same pattern.
Next test: [VC-06](../walkthroughs/VC06-MicrofrontendEstate.md) proposes compatible and
incompatible feature releases, failed loading and binding rollback across fresh and
already-open sessions. These runtime checks have not yet been executed.
already-open sessions. A bounded native-module experiment now exercises these cases; see the update below.
## Executed activation/session evidence — 2026-09-26
[Feature release experiment](../reviews/FeatureReleaseExperiment.md) meets 14/14
expected observations across two browsers in an authored native-module fixture.
Distinguish retained artifact, per-document binding and evaluated module lifetime:
a fresh session follows activation/rollback while an existing session retains its
binding; deleting the old artifact can break its delayed first load. A post-import
API check runs after evaluation and is not a security boundary. A shared startup
failure can block otherwise separate features. These are bounded mechanism observations,
not execution of the source examples or proof of full-pattern production independence.

View file

@ -141,3 +141,8 @@ sources support partial mechanisms, not verified production release independence
example and a contrast with deployment. [Evidence](../reviews/FeatureDeploymentBoundaries.md)
and [provisional VC-06](../walkthroughs/VC06-MicrofrontendEstate.md) distinguish module,
artifact, activation, runtime-failure and organizational boundaries.
Independent Feature Boundary follow-up: [native-module release cases](../reviews/FeatureReleaseExperiment.md)
add bounded execution for publication, activation, session-scoped rollback and artifact
retention. Corpus remains seventeen hypotheses; synthetic host behavior is not an
independent application use or production release guarantee.

View file

@ -148,3 +148,14 @@ Accessed 2026-09-26. [17-file hash manifest](../reviews/FeatureDeploymentSources
and [claims D01–D09](../reviews/FeatureDeploymentBoundaries.md). Static example-source
inspection, no builds or deployments run. Documentation revisions unknown; examples
and docs do not establish independent recurrence of a complete release contract.
## Native-module release experiment — 2026-09-26
SRC-0036: [feature release fixture](../experiments/feature-release/README.md), authored
synthetic host/artifacts with locked Playwright and hashed browser/input provenance.
Seven cases in Chromium/Firefox, 14/14 expected observations. Distinct from the earlier
pinned source examples; no deployed release workflow was executed.
SRC-0037: [MDN dynamic import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import#module_namespace_object),
Module namespace object; living documentation accessed 2026-09-26, exact revision
unknown. Context for evaluated module reuse versus HTTP caching. [Review](../reviews/FeatureReleaseExperiment.md).

View file

@ -0,0 +1,50 @@
# Feature publication, activation and rollback experiment
Executed 2026-09-26. Seven scenarios in Chromium 151.0.7922.34 and Firefox 155.0;
14/14 assertions met. [Review](../../reviews/FeatureReleaseExperiment.md),
[results](result.json), [provenance](provenance.json).
This is an authored synthetic host using real browser-native modules/import maps,
not execution of the earlier FSD/single-spa examples or a production release system.
The host API is fixed at 1. Reports R1/R2 support 1, R3 declares 2; Account A1 stays
unchanged. Each new HTML document receives the current map. Published assets and
activation bindings are separate in-memory controls in the test server.
## Reproduce
From this directory:
```bash
npm ci --ignore-scripts --cache /tmp/fep-npm-cache
PLAYWRIGHT_BROWSERS_PATH=/tmp/fep-playwright-browsers node node_modules/playwright/cli.js install firefox
PLAYWRIGHT_BROWSERS_PATH=/tmp/fep-playwright-browsers FEP_CHROMIUM_PATH=/path/to/chrome npm test
```
Playwright 1.63.0 is locked. Recorded runs used the same browser binaries identified
by hashes in provenance.json, with an explicit Chromium executable override. Firefox
required execution outside the workspace sandbox to access its temporary profile.
No external network is used during cases. Loopback server/browser cleanup is automatic.
Outputs default to `/tmp/fep-release-result.json` and an incomplete checkpoint at
`/tmp/fep-release-checkpoint.json`; `FEP_RESULT_PATH` overrides the final destination.
Any failed assertion produces nonzero exit. Receipts are not overwritten automatically.
## Cases and limits
| Case | Observed result in both browsers |
| --- | --- |
| X01 Publish R2 without changing binding | Fresh page still uses R1; no R2 request |
| X02 Activate compatible R2 | Fresh page R2; old loaded and old lazy pages R1; Account A1 unchanged |
| X03 Activate incompatible R3 | Host rejects mount, Account works; R3 module has already evaluated |
| X04 Point binding to missing artifact | Reports error, Account navigation still usable |
| X05 Roll binding back R2 → R1 | Fresh page R1; running page R2; explicit reload gets R1 |
| X06 Retire R1 after activating R2 | Old loaded page retains R1; old lazy page fails; new page uses R2 |
| X07 Fail shared startup module | Both navigation buttons remain disabled; feature loading never starts |
Negative controls intentionally pass when the specified failure is observed. All
responses disable HTTP caching, so this is not a CDN/cache invalidation test. Existing
pages retain their document maps; dynamic map mutation/hot replacement is not tested.
Only the host's deliberately tiny API-version contract is checked; module evaluation
can already have side effects before that check. No backend writes, authentication,
API migrations, atomic/concurrent map updates, accessibility audit or safe reload of
unsaved work is modeled. The startup outage reflects this fixture's chosen dependency,
not an assertion that every independently released frontend must fail that way.

View file

@ -0,0 +1,4 @@
export const version = 'A1';
export const hostApi = 1;
window.observed.evaluations.push(version);
export function mount(node) { node.textContent = 'Account A1'; }

View file

@ -0,0 +1,51 @@
import {chromium, firefox} from 'playwright';
import {createServer} from 'node:http';
import {once} from 'node:events';
import {readFile,writeFile} from 'node:fs/promises';
import {fileURLToPath} from 'node:url';
import {createHash} from 'node:crypto';
import assert from 'node:assert/strict';
const dir=fileURLToPath(new URL('.',import.meta.url));
const fileNames=['host.js','reports-r1.js','reports-r2.js','reports-r3.js','account-a1.js','shared.js'];
const assets=new Map(await Promise.all(fileNames.map(async f=>['/'+f,await readFile(dir+f)])));
let binding, published, sharedDown, requests;
function reset(){binding={reports:'/reports-r1.js',account:'/account-a1.js',shared:'/shared.js'};published=new Set(['/host.js','/reports-r1.js','/account-a1.js','/shared.js']);sharedDown=false;requests=[];}
reset();
const server=createServer((req,res)=>{
const path=new URL(req.url,'http://localhost').pathname;
res.setHeader('Cache-Control','no-store');
if(path==='/'){
requests.push({path,status:200,binding:{...binding}});res.setHeader('Content-Type','text/html');
res.end(`<!doctype html><html lang="en"><title>Feature release probe</title><body><nav><button id="reports-nav" disabled>Reports</button><button id="account-nav" disabled>Account</button></nav><p id="status" role="status">starting</p><section id="reports"></section><section id="account"></section><script type="importmap">${JSON.stringify({imports:binding})}</script><script type="module" src="/host.js"></script></body></html>`);
}else if(path==='/shared.js'&&sharedDown){requests.push({path,status:503});res.writeHead(503,{'Content-Type':'text/plain'});res.end('synthetic startup outage');}
else if(published.has(path)&&assets.has(path)){requests.push({path,status:200});res.setHeader('Content-Type','application/javascript');res.end(assets.get(path));}
else{requests.push({path,status:404});res.writeHead(404,{'Content-Type':'text/plain'});res.end('artifact absent');}
});
server.listen(0,'127.0.0.1');await once(server,'listening');
const url=`http://127.0.0.1:${server.address().port}`;
const results=[];
try{
for(const [engine,launcher]of [['chromium',chromium],['firefox',firefox]]){
const browser=await launcher.launch({headless:true,...(engine==='chromium'&&process.env.FEP_CHROMIUM_PATH?{executablePath:process.env.FEP_CHROMIUM_PATH}:{})});
try{
async function scenario(id,run){reset();const pages=[];const r={id,engine,browser:browser.version(),status:'pass'};
async function session(expected='ready'){const p=await browser.newPage();p.setDefaultTimeout(2500);pages.push(p);await p.goto(url);await p.locator('#status').filter({hasText:expected}).waitFor();return p;}
try{r.observation=await run(session);}catch(e){r.status='fail';r.error=e.message;}
r.sessions=await Promise.all(pages.map(p=>p.evaluate(()=>({text:document.body.innerText,observed:window.observed}))));r.requests=[...requests];results.push(r);for(const p of pages)await p.close();
await writeFile('/tmp/fep-release-checkpoint.json',JSON.stringify({status:'incomplete',results},null,2)+'\n');}
const reports=p=>p.evaluate(()=>window.loadReports());const account=p=>p.evaluate(()=>window.loadAccount());
await scenario('X01-publish-without-activation',async open=>{published.add('/reports-r2.js');const p=await open();assert.deepEqual(await reports(p),{ok:true,version:'R1'});assert(!requests.some(x=>x.path==='/reports-r2.js'));return {active:'R1',publishedButUnused:'R2'};});
await scenario('X02-compatible-activation-old-and-lazy',async open=>{
const loaded=await open();assert.equal((await reports(loaded)).version,'R1');const lazy=await open();published.add('/reports-r2.js');binding.reports='/reports-r2.js';const fresh=await open();
assert.equal((await reports(fresh)).version,'R2');assert.equal((await reports(loaded)).version,'R1');assert.equal((await reports(lazy)).version,'R1');for(const p of [loaded,lazy,fresh])assert.equal((await account(p)).version,'A1');
return {fresh:'R2',oldLoaded:'R1',oldLazy:'R1',account:'A1',hostUnchanged:true};});
await scenario('X03-incompatible-module',async open=>{published.add('/reports-r3.js');binding.reports='/reports-r3.js';const p=await open();assert.deepEqual(await reports(p),{ok:false,message:'incompatible host API'});assert.equal((await account(p)).version,'A1');const o=await p.evaluate(()=>window.observed);assert(o.evaluations.includes('R3'));assert(!o.mounts.some(x=>x.name==='reports'));return {incompatibleMountRejected:true,moduleAlreadyEvaluated:true,accountUsable:true};});
await scenario('X04-missing-artifact',async open=>{binding.reports='/missing.js';const p=await open();assert.equal((await reports(p)).ok,false);await p.locator('#account-nav').click();await p.locator('#account').filter({hasText:'Account A1'}).waitFor();assert(requests.some(x=>x.path==='/missing.js'&&x.status===404));return {localLoadFailure:true,navigationUsable:true};});
await scenario('X05-rollback-fresh-versus-running',async open=>{published.add('/reports-r2.js');binding.reports='/reports-r2.js';const old=await open();assert.equal((await reports(old)).version,'R2');binding.reports='/reports-r1.js';const fresh=await open();assert.equal((await reports(fresh)).version,'R1');assert.equal((await reports(old)).version,'R2');await old.reload();await old.locator('#status').filter({hasText:'ready'}).waitFor();assert.equal((await reports(old)).version,'R1');return {freshAfterRollback:'R1',runningBeforeReload:'R2',afterExplicitReload:'R1'};});
await scenario('X06-retired-old-artifact',async open=>{const loaded=await open();assert.equal((await reports(loaded)).version,'R1');const lazy=await open();published.add('/reports-r2.js');binding.reports='/reports-r2.js';published.delete('/reports-r1.js');assert.equal((await reports(loaded)).version,'R1');assert.equal((await reports(lazy)).ok,false);const fresh=await open();assert.equal((await reports(fresh)).version,'R2');return {oldLoadedStillWorks:true,oldLazyFails:true,newSession:'R2'};});
await scenario('X07-shared-startup-outage',async open=>{sharedDown=true;const p=await open('startup failed');assert.equal(await p.locator('#reports-nav').isDisabled(),true);assert.equal(await p.locator('#account-nav').isDisabled(),true);assert(requests.some(x=>x.path==='/shared.js'&&x.status===503));assert(!requests.some(x=>x.path==='/reports-r1.js'));return {bothNavigationActionsBlocked:true,featureLoadingNeverStarted:true};});
}finally{await browser.close();}
}
}finally{await new Promise(resolve=>server.close(resolve));}
const files={};for(const f of [...fileNames,'experiment.mjs','package.json','package-lock.json'])files[f]=createHash('sha256').update(await readFile(dir+f)).digest('hex');
const output=process.env.FEP_RESULT_PATH||'/tmp/fep-release-result.json';const result={date:new Date().toISOString(),node:process.version,kind:'synthetic-native-es-module-browser-experiment',files,results,passed:results.filter(x=>x.status==='pass').length,total:results.length};await writeFile(output,JSON.stringify(result,null,2)+'\n');console.log(JSON.stringify({output,passed:result.passed,total:result.total,failures:results.filter(x=>x.status==='fail')},null,2));if(result.passed!==result.total)process.exitCode=1;

View file

@ -0,0 +1,29 @@
const HOST_API = 1;
window.observed = {mounts: [], errors: [], evaluations: [], hostApi: HOST_API};
const report = document.getElementById('reports');
const account = document.getElementById('account');
async function load(name, target) {
try {
const feature = name === 'reports' ? await import('reports') : await import('account');
// Compatibility gate, not a security boundary: module evaluation already happened.
if (feature.hostApi !== HOST_API) throw new Error('incompatible host API');
feature.mount(target);
window.observed.mounts.push({name, version: feature.version});
return {ok: true, version: feature.version};
} catch (error) {
target.textContent = `${name} unavailable`;
window.observed.errors.push({name, message: error.message});
return {ok: false, message: error.message};
}
}
window.loadReports = () => load('reports', report);
window.loadAccount = () => load('account', account);
try {
await import('shared');
for (const button of document.querySelectorAll('button')) button.disabled = false;
document.getElementById('status').textContent = 'ready';
} catch {
document.getElementById('status').textContent = 'startup failed';
}
document.getElementById('reports-nav').onclick = window.loadReports;
document.getElementById('account-nav').onclick = window.loadAccount;

View file

@ -0,0 +1,40 @@
{
"name": "fep-feature-release",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "fep-feature-release",
"dependencies": {
"playwright": "1.63.0"
}
},
"node_modules/playwright": {
"version": "1.63.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
"integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==",
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.63.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=20"
}
},
"node_modules/playwright-core": {
"version": "1.63.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz",
"integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==",
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=20"
}
}
}
}

View file

@ -0,0 +1,7 @@
{
"name": "fep-feature-release",
"private": true,
"type": "module",
"scripts": {"test": "node experiment.mjs"},
"dependencies": {"playwright": "1.63.0"}
}

View file

@ -0,0 +1,28 @@
{
"date": "2026-09-26",
"packages": {
"node_modules/playwright": {
"version": "1.63.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
"integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg=="
},
"node_modules/playwright-core": {
"version": "1.63.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz",
"integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg=="
}
},
"chromium": {
"version": "151.0.7922.34",
"executable_sha256": "0b20b130e7edd9dd51873be867761295fe0cfad490c2b9a64f95bd3cfc08fa71",
"selection": "preinstalled Chromium build 1234, explicit executable override; not claimed to be Playwright 1.63 bundled revision"
},
"firefox": {
"playwright_build": "1543",
"executable_sha256": "062272ac4d851eade5b75db2dc7c14569d96cb3ca38f949337cdc1b74367e35b",
"version": "155.0"
},
"execution": "Local loopback server, native ES modules and import maps; synthetic host/artifacts; no production or single-spa deployment",
"http_cache": "All responses use Cache-Control: no-store; no service worker or CDN",
"activation": "Runner changes an in-memory binding used only in newly served documents; no client hot-rebinding or concurrent deployment protocol"
}

View file

@ -0,0 +1,4 @@
export const version = 'R1';
export const hostApi = 1;
window.observed.evaluations.push(version);
export function mount(node) { node.textContent = 'Reports R1'; }

View file

@ -0,0 +1,4 @@
export const version = 'R2';
export const hostApi = 1;
window.observed.evaluations.push(version);
export function mount(node) { node.textContent = 'Reports R2'; }

View file

@ -0,0 +1,4 @@
export const version = 'R3';
export const hostApi = 2;
window.observed.evaluations.push(version);
export function mount(node) { node.textContent = 'Reports R3 incompatible'; }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
export const sharedVersion = 'S1';

View file

@ -103,3 +103,9 @@ separate repositories prove none of the latter guarantees by themselves.
[VC-06](../walkthroughs/VC06-MicrofrontendEstate.md) changes only release cadence to
show why source boundaries can remain while deployment units merge. Runtime version
skew/rollback and independent assessment remain open; Q06 is not closed.
Q06 lifecycle follow-up: [release experiment](../reviews/FeatureReleaseExperiment.md)
distinguishes artifact retention, document binding and module-instance lifetime.
Old delayed loads can fail after artifact retirement even while already-loaded old
sessions work. Deployment independence remains conditional on a session-support
contract; no general answer or canonical promotion follows from this fixture.

View file

@ -70,3 +70,9 @@ activation binding with both fresh and already-running sessions. Check startup-c
shared resources separately from feature-local failure. Do not use existing deployment
workflows or credentials to perform the experiment; a local controlled harness suffices.
Q06 is sharpened, not closed. No additional inference was needed for this review.
## Executed synthetic follow-up
[Feature release experiment](FeatureReleaseExperiment.md) now exercises the proposed
version/load/rollback cases in an authored native-module host. This does not change
the static-only status of the upstream repositories inspected above.

View file

@ -0,0 +1,58 @@
# Feature release lifecycle experiment — 2026-09-26
Status: executed synthetic browser mechanism, editorial interpretation by Codex.
WP-0003 T01, following [source/deployment contrast](FeatureDeploymentBoundaries.md).
The [fixture and receipt](../experiments/feature-release/README.md) record seven cases
in two browsers, 14/14 expected observations. Seventeen hypotheses remain unchanged
in maturity; no production deployment, operational team independence or recurrence
is established. No model calls were needed.
## Evidence and provenance
SRC-0036 is our native-module host and versioned feature fixtures, executed with
Playwright 1.63.0, Chromium 151.0.7922.34 and Firefox 155.0. Source/lock hashes are in
the result receipt; browser hashes and package integrity are in provenance.json.
Every response uses no-store, and the loopback server serves no external resources.
SRC-0037: [MDN import()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import#module_namespace_object),
Module namespace object, accessed 2026-09-26, living revision unknown. Its description
of reuse after successful module loading provides context for distinguishing module
identity from HTTP caching. We do not generalize our document-map snapshot policy to
all loaders or dynamic import-map update strategies.
## Observations, not deployment guarantees
| Evidence | Result | Pattern implication |
| --- | --- | --- |
| X01 | Publishing R2 alone leaves new pages on R1 | Artifact availability and activation are separate |
| X02 | Fresh page loads R2; old loaded/lazy pages load or retain R1; A1 unchanged | Compatible feature activation can coexist with an unchanged host and neighbor in this fixture; old-session binding matters even before first feature use |
| X03 | R3 is evaluated but mounting is rejected for host API mismatch; A1 works | Post-import contract checks can prevent incompatible mounting, but cannot undo module side effects or provide security isolation |
| X04 | Missing Reports module yields local error while Account navigation works | Host-level load handling is distinct from a component rendering boundary |
| X05 | Binding rollback changes a fresh page to R1 while an open page remains R2; reload selects R1 | Rollback needs a declared session scope; binding update alone is not hot replacement |
| X06 | Removing R1 breaks the old lazy session but not one that already loaded it | Artifact retention must account for delayed first loads from supported older documents |
| X07 | Shared startup import failure keeps both actions disabled, before any feature load | Separate artifacts do not eliminate dependencies on startup-critical shared resources |
X03, X04, X06 and X07 include deliberately observed failures. A “pass” means the
asserted behavior occurred, not that the experience is acceptable. The version gate
is our fixture code, not a universal browser, single-spa or federation guarantee.
The R3 declaration is intentionally simple; real API compatibility is not reducible
to equality of one number. Test outcomes do not prove compatibility with arbitrary
host/backend versions or that deployment changes are applied atomically.
## Candidate and walkthrough correction
[Independent Feature Boundary](../candidates/IndependentFeatureBoundary.md) should
name three lifetimes separately: retained artifact, binding chosen for a session,
and module instance already evaluated in that session. Retiring an artifact based
only on the current global binding can invalidate an older page's later load.
[VC-06](../walkthroughs/VC06-MicrofrontendEstate.md) now has executable support for
its load/activation/rollback distinction in this small model. Its accessibility,
real-system compatibility, authoritative writes and independent assessment remain
open. The earlier pinned examples were not run; their source observations remain
separate. Keep the pattern a hypothesis and the walkthrough provisional.
Next under WP-0003 T01: declare an old-session support/retention policy, then test
activation-map concurrency and safe reload with unfinished work before making a
production recommendation. Navigation/history/cache evidence remains pending. Avoid
turning this model into a release platform merely to close the research question.

View file

@ -90,3 +90,17 @@ Vertical Feature Slice need not imply Independent Feature Boundary.
version-skew/load-failure/binding-rollback harness and independent walkthrough review.
No cloud deployment, production artifact activation or operational team independence
was verified. VC-04/05 remain planned; this draft does not complete VC-06's M2 gate.
## Executed model follow-up — 2026-09-26
[Seven-scenario native-module experiment](../reviews/FeatureReleaseExperiment.md)
now supports steps 2–6's publication/activation, version mismatch, failed loading and
session-scoped rollback distinctions in a synthetic host. Both browsers meet all seven
expected observations, including deliberate failures. Old lazy sessions need retained
artifacts even when loaded old sessions still work. Post-import compatibility gates
cannot prevent evaluation side effects. Shared startup outage is a separate fault scope.
This supersedes the lack of any load/rollback execution in the initial self-review,
but the quality criterion remains revise: browser focus/accessibility, unsaved work,
real API/data compatibility and independent review are still unverified. VC-06 stays
provisional; no production release or M2 acceptance is inferred.

View file

@ -150,3 +150,21 @@ host, failed load, activation rollback with fresh and already-running sessions,
shared startup outage. No production workflows/credentials needed. Navigation checks
and broader router-lifecycle limits remain live; T03 and human-validation gate unchanged.
No model calls, deployment, canonical admission or proven generativity benefit.
## Native-module publication/activation/rollback experiment — 2026-09-26
T01 progress: research/experiments/feature-release executes seven scenarios in
Chromium/Firefox, 14/14 expected observations. Compatible R2 activation changes fresh
sessions, not old document bindings; incompatible R3 evaluates before mount rejection;
404 feature failure preserves neighbor navigation; rollback affects fresh/reloaded
sessions; retiring R1 breaks old lazy sessions while loaded R1 persists; shared startup
503 blocks both actions by fixture policy. No CDN, live deployment, backend writes,
model calls or execution of upstream example workflows. Inputs/packages/browser hashes
and request traces recorded; negative controls distinguished from desirable behavior.
Independent Feature Boundary and provisional VC-06 updated, seventeen hypotheses.
Next T01 limits: old-session retention/support policy, concurrent activation updates,
safe reload with unfinished work; navigation/history/cache evidence remains pending.
Do not build a production release platform to satisfy this research model. T02/T03,
independent-human gate and M1/M2 completion remain unchanged.
See research/reviews/FeatureReleaseExperiment.md.