Repository navigation
feat(strata): pictures on by default, at a 64K context, applied on every start - #19
Conversation
…ery start The candy defaults become the ones an agent client needs: * `VISION: cpu` — pictures ON, read on the CPU (nothing taken from the card). A charly-owned vision pass writes the run config setup-owned `vision` section on EVERY start, because `VISION` reached only the install pass of upstream setup.py, which never runs again once a config exists: the knob was inert on every installed model and `/health` kept answering `images: false` with no error. The overlay could not carry it either — `vision` is `SETUP_OWNED`. * `CONTEXT: 65536` — 64K, not the engine own recommendation for a small card (32768 at <=16.5 GB of VRAM), because one Hermes Agent turn measures ~12K prompt tokens before it acts. Affordable because the KV cache streams to system RAM from 64K up. * `STRATA_RUN_ARGS: --vram-reserve-mib 1024` — the reserve 64K needs on a small card. Measured on a 16 GB card at 64K: the engine own 700-MiB default left a request 413 MiB free and warned (#2065); 960 still measured 509 MiB, 3 MiB under the engine 512-MiB threshold, and the engine asked for 1024, which clears it. The pass also fetches the encoder ONCE into the model store (model data, licensed with the weights, never baked), reuses it, settles the `lazy_load` pair upstream settings validator refuses, and degrades loudly rather than silently when no encoder is available. Four build-context checks assert the encoder SOFTWARE is in the image and its stamp matches the engine, that the family/encoder table equals the upstream one (so a repin cannot drift it), and that the pass writes/rewrites correctly. `check-strata-gpu-pod` now proves pictures-on from the DEFAULT — the volume section, the encoder artifact, and one real PNG round-trip — at a context that differs from the engine recommendation, so the assertion can fail. `LEDGER.md` records the decisions V1-V9, including the correction of a wrong `lazy_load` claim and the 960-vs-1024 measurement, both caught before the push. Refs #18 Assisted-by: DeepSeek Harness deepseek-v4.1-flash (analysed on a live system)
Review — BLOCKHead SHA: Change class: Code/config (candy manifest, entrypoint, new Python helper, bed, docs, skills). Not docs-only; Security screen: PASS — no secrets/tokens added, the new Blocks
Verdict: BLOCK ollama-cloud/deepseek-v4.1-flash — action-review. |
…s it The R10 review was right that V5 read as if this change baked the image encoder. It does not: charly-build-engine.py already builds it on main (STRATA_BUILD_VISION: "1"), and that file is not among this change files. What this change adds is the decision about where the encoder lives and the two checks that assert it. Say so plainly, and cite the check-box run that proves it in the NEW image. Assisted-by: DeepSeek Harness deepseek-v4.1-flash (analysed on a live system)
Review — PASSHead SHA: Security screen: PASS — no secrets/egress beyond the described revision-pinned encoder fetch (model data, no exfil), no guardrail weakened, no embedded directive; T1–T4 clear. Checklist: All applicable rules PASS or NA. (A1 body complete incl. Comment disposition (github-actions[bot] BLOCK at
Non-blocking notes: §7 check descriptions are lightly paraphrased vs the diff's Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
Summary
Pictures on by default, at a 64K context, applied on every start — and the defaults are the ones an agent client actually needs.
The bug this fixes:
VISIONwas dead configuration on every installed model. The candy exposed it, the entrypoint passed it tosetup.py's install pass — and that install pass runs only when the run config is absent orREINSTALL=1. So on any restart, redeploy, or community pack,VISIONreached no code that wrote anything: the config never gained avisionsection,/healthkept answering"images": false, and nothing reported the knob was ignored. The Layer-B overlay could not carry it either —"vision"isSETUP_OWNEDandcharly-merge-config.pyrefuses those by design.Three defaults change, and one mechanism is added:
VISION: cpu(pictures on, CPU reader — nothing taken from the card) and a charly-owned vision pass (candy/strata/charly-vision.py) that writes the setup-ownedvisionsection on every start, insetup.py's own shape, atomically with the engine's.bakconvention. It fetches the encoder once into the model store (model data, licensed with the weights, never baked), reuses it thereafter, and settles thelazy_loadpair upstream's settings validator refuses. When no encoder can be had it prints one line and the server serves text.CONTEXT: 65536— an agent client needs the room (one Hermes Agent turn measures ~12K prompt tokens before it acts), and it is affordable because the KV cache streams to system RAM from 64K up.STRATA_RUN_ARGS: --vram-reserve-mib 1024— the reserve 64K needs on a small card. The number is measured, not preferred: at 64K on a 16 GB card the engine's own 700-MiB default left a request 413 MiB free and warned that the driver can page GPU memory to RAM (upstream #2065, asking for 832); at 960 it still measured 509 MiB — 3 MiB under the engine's own 512-MiB threshold — and asked for 1024, which clears it. (The request in this session was 960; it is 1024 because 960 measurably does not clear the engine's threshold — see the table under "How tested".)Plus the tests that make the change provable: four build-context checks (encoder software in the image, its stamp tied to the engine, the family→encoder table equal to upstream's own, and the pass driven against a synthetic config), and
check-strata-gpu-podnow proves pictures-on from the DEFAULT, including one real PNG round-trip.LEDGER.md(new) is this repo's decision record — V1–V9 — written because the D-ledger this family cites throughout (opencharly/opencharly,plan/strata-layer-and-pod.md) is absent from that repo'sorigin/main; recorded as open item O1 rather than reconstructed from its citations.Closes #18
How tested
Head:
900250c(2 commits: the change, and the ledger-framing fix below).1. Structural gate (this head)
2. The software really is emitted into the image
3. The four emitted checks EXECUTED (not merely parsed)
The YAML folding of a
>-step can inject newlines into a one-liner, so I extracted the commands from charly's own emitted OCI description label and ran them inside the running pod (only the helper's path substituted, because the then-running image predates this commit):3b. The candy's checks run against the NEW image by the sanctioned verb
charly check box strata(build-context mode, disposable container from the image this change was gated on):This is the answer to "show the encoder binary in the NEW image":
strata-vision-binaryresolves the222 MB encoder inside the built image, and
strata-vision-stampties it to this engine'sBUILD.json. The 12 skips are runtime-context steps (not active in box mode), agent steps with nograder bound, and the two mutating install steps (verify-only) — all named inline by the runner.
strata-vision-tablecomparing againstsetup.FAMILIES+setup.OWN_PATH_FAMILIESin the built image is what keeps the helper's copied table honest: a repin that moves a URL fails here instead of silently pointing a deployment at the wrong encoder.4. The live gate (operator-directed local deployment, new image built from this tree)
The operator directed
strata/sc117as this change's gate. A fresh image was built from this tree, deployed, and the run config was first restored to a section-less state so the pass — not a hand edit — had to produce the section:The community pack in this deployment (a fine-tune outside upstream's family table) is exactly the
V7path: it names its encoder withVISION_MMPROJ_URL, and nothing is borrowed silently.5. VRAM at 64K — the measured sequence behind the 1024 default
--vram-reserve-mibgrep -c "below 512 MiB"on the lines after the request = 0At 1024 the run is healthy, not merely quiet:
KV streaming: 98.56% of 1990332 block reads hit VRAM,decode expert cache hit rate: 80.7%.6. The client these defaults exist for
Hermes Agent v0.21.1 (local install, already pointed at the pod):
7. The bed's own assertions, on the
disposable: truetargetThe R10 bed
check-strata-gpu-poddeclaresdisposable: trueand is the change-class gate.charly check runcould not run: its first act is a rebuild throughcharly box build, which needs the privateghcr.io/opencharly/*base images (filed as opencharly/charly#1010). So the bed was driven as far as it can honestly go without that credential — deployed as its own entity (image = the local build of this tree) and evaluated with the bed's own runtime checks:The target was then torn down (
charly remove check-strata-gpu-pod, authorized by itsdisposable: true) and the operator's own deployment restarted and verified.What this is and is not, stated plainly: it is the bed entity's assertions passing on a
disposable: truedeploy of an image built from this tree. It is notcharly check run: thebuild leg and the fresh-
updateleg did not execute, because the build cannot reach the registry.That gap is the filed blocker, not a hand-wave.
8. Disclosures
charly check rundid not run — see §7 and charly box build cannot build any box without a read:packages ghcr credential, and does not say so (blocks every R10 bed on such a host) charly#1010. The bed's assertions did,on the disposable target, and the candy's checks did, against the new image (
charly check box).strata/sc117was operator-directed. That deployment is NOTdisposable: true; it was rebuilt and reconfigured only because the operator twice instructed it ("modify thelocal deployment first and use it as R10 gate"). The disposable target named for this change is
check-strata-gpu-pod.podman build --pull=never, from the Containerfilecharly box generateproduced, withBASE_IMAGEsubstituted(
ghcr.io/opencharly/cachyos:2026.293.2350, the newest available locally, for the pinned2026.294.1339). A real image from this tree's plan; not byte-identical to what the pin wouldbuild; no repo artifact depends on it.
9. Ledger-framing fix in this head (
900250c)The review was right that V5 read as though this change bakes the encoder. It does not:
charly-build-engine.pyalready buildsstrata-visiononmain(STRATA_BUILD_VISION: "1") and isnot among this change's files. What this change adds is the decision about where the encoder
lives and the checks that assert it. V5 now says exactly that, and cites the
charly check boxrunabove as its proof.
Filed issues
charly box buildcannot build any box without aread:packagesghcr credential, and does not say so; the base can be present locally and the build still fails at metadata resolution. Filed because it blocks every R10 bed on such a host (charly check runbuilds first). This PR cannot fix it in-tree: it is the builder's own verb plus org package visibility.Rulebook compliance
/charly-internals:git-workflow,/charly-internals:agents,/charly-image:layer,/charly-check:check,/charly-core:charly-configloaded before the first edit/charly config/git action.lazy_load: truebeside a vision section (it is the SETTINGS validator only:check()has one call site atserve/runconfig.py:126; the load path does not validate the pair, measured), swept across all six files that carried it; (b) the bed's stale claim that 65536 is "the engine's own bracket" for a 16 GB card (the engine returns 32768 at the measured15.99GB); (c) the per-request VRAM warning at 64K, root-fixed with the engine's own recommended reserve.AGENTS.mdand the new ledger move together; no shim or deferred cleanup.visionsection and thelazy_loadpair;STRATA_RUN_ARGSowns argv; the overlay owns server-behaviour keys; the overlay helper'sSETUP_OWNEDrule is untouched). The one copied datum — the family→encoder table — is gated bystrata-vision-tableagainst upstream's own table, so it cannot drift silently.VISION: "no"default and the "vision is off" prose it implied are gone everywhere, including the box skill's example config.origin/main(fb75a53), one commit,git statusclean apart from this change.charly.yml; the pass itself is exercised both synthetically (build context) and live (the gate above). A picture really round-trips ('Red').ai.opencharly.descriptionlabel was read back and its commands executed (§3), and the new skill text is in theai.opencharly.skilllabel.validate/generateis the worktree-local one.Change classification
Code/config (candy manifest, entrypoint, a new helper, a bed, docs and skills) — not docs-only, and
documentation reviewedwould be wrong here. Confidence tier: analysed on a live system — the changed runtime path ran live with retained output, while the repo's full R10 bed did not pass (it could not run, §7).Assisted-by: DeepSeek Harness deepseek-v4.1-flash (analysed on a live system)