A personality belongs to a person
Owner's correction to 1.4.0: a model's character is per (model, person), and only the description and the notes stay instance-wide. Two people talking to one model are not talking to the same personality, and neither can see the other's. The administrator's box becomes the DEFAULT, resolved by `personas.effective` as a fallback and never as a layer -- two personalities at once contradict each other with nothing to say which is losing, which is the reasoning behind "system prompts replace, never stack". `persona_write` takes no argument naming a model or a person; both come from the ToolContext, so it can only write the character it has with whoever it is talking to, and it never touches the default. Impressions move to their own table. Not a `kind` column: 1.4.0 shipped `UNIQUE(model_key, owner_id)`, SQLite cannot alter a constraint and this schema is additive-only, so a discriminator would leave an upgraded instance unable to hold both rows for one pair. That leaves the first MANUAL_STEPS entry this project has had -- the two shapes are indistinguishable, so nothing rewrites them: a repair would be guessing at text that is read back in the first person. TWO BUGS FROM A PHONE `min-width` beats both `width` and `max-width` -- CSS clamps width to max-width and then raises the result to min-width -- so `.canvas` and `.terminal` were 384px wide on every screen narrower than that, their `min(…, 100vw)` cap overruled, and `.inspector` had no cap at all on a width that is a preference draggable to 2400px. None of it scrolled sideways, because all three are `position: fixed` and fixed overflow does not extend the scrollable area -- which is exactly why the 1.1.0 narrow pass reported these pages clean. `min-width: 0` in the overlay query, full width below the phone breakpoint, tablet column kept. And the install button now says why it is absent. Measured against the live instance: the manifest meets every Chrome criterion and the blocker is a certificate from a private CA, so the origin is not trustworthy, the service worker is refused and no install is offered. `base.html` had been swallowing that with an empty catch -- which kept the page working, the reason it was there, and threw away the only evidence. It now records the outcome and `app.js` turns it into a sentence naming the certificate, which is the cause the old hint did not mention. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -655,13 +655,72 @@
|
||||
event.preventDefault();
|
||||
installPrompt = event;
|
||||
revealInstall(true);
|
||||
describeInstall();
|
||||
});
|
||||
|
||||
window.addEventListener("appinstalled", function () {
|
||||
installPrompt = null;
|
||||
revealInstall(false);
|
||||
describeInstall();
|
||||
});
|
||||
|
||||
/* Why there is no Install button, in a sentence.
|
||||
|
||||
Every reason looks identical from the outside -- the button is simply not
|
||||
there -- and the hint beside it used to say "only offered over HTTPS or on
|
||||
localhost", which is true of one of the four cases and useless for the other
|
||||
three. The commonest on a home network is the one it did not mention: a
|
||||
certificate signed by your own CA, which the phone does not trust, so the
|
||||
page is not a secure context and the worker is refused. That is
|
||||
indistinguishable, without this, from a browser that cannot install at all.
|
||||
|
||||
`textContent`, never innerHTML: `detail` is a browser's error message, and
|
||||
while a browser is not a hostile source it is not ours to trust either. */
|
||||
function installExplanation() {
|
||||
var worker = window.lembasWorker || {};
|
||||
if (window.matchMedia && window.matchMedia("(display-mode: standalone)").matches) {
|
||||
return "Already installed \u2014 you are using the installed app now.";
|
||||
}
|
||||
if (installPrompt) return "";
|
||||
if (worker.state === "insecure") {
|
||||
return (
|
||||
"This page is not a secure context, so the browser will not install it. " +
|
||||
"That means plain http, or https with a certificate this device does not " +
|
||||
"trust \u2014 a private or self-signed certificate has to be installed on " +
|
||||
"the device before any browser will treat the site as secure."
|
||||
);
|
||||
}
|
||||
if (worker.state === "failed") {
|
||||
return (
|
||||
"The service worker could not be registered, so the browser will not " +
|
||||
"offer an install. The usual cause is a certificate this device does not " +
|
||||
"trust. The browser said: " + worker.reason +
|
||||
(worker.detail ? " \u2014 " + worker.detail : "")
|
||||
);
|
||||
}
|
||||
if (worker.state === "unsupported") {
|
||||
return "This browser does not support installing. On iOS, use Share \u2192 Add to Home Screen.";
|
||||
}
|
||||
if (worker.state === "ready") {
|
||||
return (
|
||||
"Everything this end is ready and your browser has not offered an " +
|
||||
"install. Some never do \u2014 Firefox and desktop Safari \u2014 and Chrome " +
|
||||
"will not offer one twice for the same app."
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function describeInstall() {
|
||||
var text = installExplanation();
|
||||
document.querySelectorAll("[data-install-status]").forEach(function (el) {
|
||||
el.textContent = text;
|
||||
el.hidden = !text;
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("lembas:worker", describeInstall);
|
||||
|
||||
/* --- Panels ------------------------------------------------------------- */
|
||||
/* A panel can be opened or closed by more than one control -- the button in
|
||||
the topbar and the panel's own Close -- and it can now also be closed by
|
||||
@@ -963,6 +1022,11 @@
|
||||
stylesheet decides whether the drawer is showing; this is the one place
|
||||
that can ask it and say so. */
|
||||
syncToggles("#sidebar", sidebarOpen());
|
||||
|
||||
/* The worker may already have answered before this runs, in which case the
|
||||
event has been and gone -- so the state is read here as well as listened
|
||||
for. Either path, never both mattering. */
|
||||
describeInstall();
|
||||
});
|
||||
|
||||
/* A drawer that is dismissed by tapping beside it should be dismissed by
|
||||
|
||||
Reference in New Issue
Block a user