From 766e2b9d376130da34899bef4dfb4e45efa6b685 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Sun, 4 Oct 2026 18:53:17 -0400 Subject: [PATCH 1/2] docs: select mounted producer-bearing routes for retirement --- ...wer-retirement-mounted-routes-20261004.rst | 59 +++++++++++++++++++ .../use-openhcs/references/viewer-qa.md | 8 ++- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 docs/validation/viewer-retirement-mounted-routes-20261004.rst diff --git a/docs/validation/viewer-retirement-mounted-routes-20261004.rst b/docs/validation/viewer-retirement-mounted-routes-20261004.rst new file mode 100644 index 0000000000..272e7659bd --- /dev/null +++ b/docs/validation/viewer-retirement-mounted-routes-20261004.rst @@ -0,0 +1,59 @@ +Select mounted producer-bearing routes for viewer retirement +=========================================================== + +Source checkpoint: main01044edbc13c9a234a7ec52f772acca8015ccc99, +2026-10-04. Singer owns this narrow viewer-guide correction. Current open522 +retirement/selection and Planck's independent point-highlight investigation +are coordinated; open697 final summaries and693 analytical colour rendering +are disjoint. No production, dependency, runtime or scientific files change. + +Determining relation +------------------- + +Viewer state deliberately includes declared routes without a mounted layer. +NapariViewerProjectionABC.route_keys unions route titles and component groups; +layer_state_for projects mounted from the actual layer and producer_identities +from the original NapariComponentGroupStore.producer_identities_for. An +unmounted, zero-item route can correctly have an empty producer array. + +ViewerLayerRetirementControlOptions rejects empty producer tuples before +dispatch. Native NapariComponentAwareDisplayCoordinator.retire_layers also +requires every selected route to be mounted and its exact producer set to +match before any removal. This protects whole-set atomic admission, not a +ban on null invocation_key. Original PolyStore StreamProducerIdentity declares +invocation_key optional and its from_payload decoder preserves None; the +request annotation delegates to that decoder through BeforeValidator. + +The retained refused request selected eleven routes: eight populated producer +arrays plus three empty arrays. Original readback marks those three unmounted +and zero-item. The generic error is consistent with the empty-set guard, not +evidence that a null invocation_key or a valid mounted producer is rejected. +The original request, error and subsequent scene remain untouched. No replay +or author feedback occurs. No unsupported retirement fallback is introduced. + +Owner and change +---------------- + +The declared manifest source for openhcs_viewer_qa is the existing packaged +references/viewer-qa.md; this guide has no RST backer. Its retirement procedure +now explicitly chooses mounted entries with nonempty returned producer arrays, +omits unmounted placeholders, and preserves null optional identity fields. +The declaration/decoder/coordinator remain the same owners; no copied identity +codec, route selector, store, registry, guard or alternate guide is added. + +Applicable review: BOUND-2 (use the existing producer decoder), IDEN-7 (a +declared route is not necessarily a mounted layer), and IDEN-6 (exact route and +producer incarnation, not title or port). Skill-creator limits this to the +missing operational distinction; Diataxis keeps it in the existing how-to +step, rather than creating a protocol reference or a new universal gate. + +Qualification checkpoint +------------------------ + +Offline actual SDK/request-chain acceptance and ordinary knowledge projection, +packaged guide availability and managed-sync checks are pending. The former +will decode the original saved values without dispatching a mutation; the +latter will expose the same canonical bytes in disposable owned test roots. +This documentation change does not claim a new native retirement, selected +geometry-survivor acceptance, autonomous gain or installed scientific update. +Existing active/frozen author packages remain unchanged. CI deferred. diff --git a/packaging/codex/openhcs/skills/use-openhcs/references/viewer-qa.md b/packaging/codex/openhcs/skills/use-openhcs/references/viewer-qa.md index 0d624be258..28ca6bb7f3 100644 --- a/packaging/codex/openhcs/skills/use-openhcs/references/viewer-qa.md +++ b/packaging/codex/openhcs/skills/use-openhcs/references/viewer-qa.md @@ -190,9 +190,15 @@ contract is exposed: 2. Read fresh, unfiltered viewer state on the same viewer incarnation. Choose only explicitly superseded routes; retain the current matched candidate, raw/source domain and reference routes still needed for the next comparison. + Select only entries with `mounted=true` and a nonempty `producer_identities` + array. State can also list declared, unmounted routes with empty arrays; + omit those placeholders from the retirement mapping, rather than sending + `[]` or inventing an identity for them. Build `expected_producers` by mapping each chosen **exact `route_key`** to its **complete `producer_identities` array** from that readback, including - `invocation_key`. Do not shorten, fabricate or substitute identities from a + `invocation_key`; preserve `null` when that is the returned value. It is a + valid optional identity field, not a missing producer. Do not shorten, + fabricate or substitute identities from a previous candidate, title or port. The receiving owner checks the whole set before removal; a changed producer requires a fresh disposition/readback, not a weaker identity check. From 44bb106a8e2490770ef5da9fa78bfc58cf80783c Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Sun, 4 Oct 2026 19:00:35 -0400 Subject: [PATCH 2/2] docs: qualify retirement selection through original SDK and guide owners --- ...wer-retirement-mounted-routes-20261004.rst | 67 ++++++++++++++++-- ...-retirement-mounted-routes-20261004.tar.gz | Bin 0 -> 18762 bytes ...test_viewer_retirement_guide_projection.py | 13 +++- 3 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 docs/validation/viewer-retirement-mounted-routes-20261004.tar.gz diff --git a/docs/validation/viewer-retirement-mounted-routes-20261004.rst b/docs/validation/viewer-retirement-mounted-routes-20261004.rst index 272e7659bd..bddc3cde75 100644 --- a/docs/validation/viewer-retirement-mounted-routes-20261004.rst +++ b/docs/validation/viewer-retirement-mounted-routes-20261004.rst @@ -25,9 +25,15 @@ invocation_key optional and its from_payload decoder preserves None; the request annotation delegates to that decoder through BeforeValidator. The retained refused request selected eleven routes: eight populated producer -arrays plus three empty arrays. Original readback marks those three unmounted -and zero-item. The generic error is consistent with the empty-set guard, not -evidence that a null invocation_key or a valid mounted producer is rejected. +arrays plus three empty arrays. An earlier readback marks those three unmounted +and zero-item; the latest readback before retirement instead has them mounted, +with one item and populated producer identities. The request retained their +older empty arrays. The generic error is consistent with the empty-set guard, +not evidence that null invocation_key or a valid fresh mounted producer is +rejected. The first offline evidence assertion expected complete latest-state +parity and failed; that determining failure is preserved, not weakened or +misclassified as a product failure. Eight supplied populated identities match +the latest state exactly; the three stale empty entries do not. The original request, error and subsequent scene remain untouched. No replay or author feedback occurs. No unsupported retirement fallback is introduced. @@ -50,10 +56,57 @@ step, rather than creating a protocol reference or a new universal gate. Qualification checkpoint ------------------------ -Offline actual SDK/request-chain acceptance and ordinary knowledge projection, -packaged guide availability and managed-sync checks are pending. The former -will decode the original saved values without dispatching a mutation; the -latter will expose the same canonical bytes in disposable owned test roots. +Offline SDK acceptance used the ORIGINAL installed receiving04 target and paired +interpreter, not a modified client or native process. build_server constructed +the actual registered retirement Tool's argument model. It decodes the original +eleven-entry request, after which the original request/control-options owner +rejects its three empty arrays with the exact retained error. Independently +constructing the eight populated, mounted entries preserves every returned +producer field through SDK -> original DTO -> as_tool_arguments, including +all null invocation_key values. No tool.run, transport send, native request, +client startup or viewer mutation was issued: dispatches0. + +sdk01 retained the first evidence assertion failure described above. sdk02 is +terminal0,7.36s,377876KiB maxRSS,Swap0. Both journal hashes remain unchanged; +their complete original paths/hashes, imported module paths/hashes and outcomes +are retained in the archive. Relevant owner ASTs are equal between current +source and this original installed target: retirement control-options, +request, result and native retire_layers. This is actual SDK/request admission, +not a new public TCP retirement or survivor remount. + +The existing audit Package/Repository AST owners parsed all701 production and +705 test modules at source766e2b9d3, zero omissions,32.83s/990724KiB/Swap0. +The selected direct consumers are capability declaration, request/result DTO, +original viewer-window service/gateway, CLI command and native coordinator; +two existing native/SDK test modules consume them. The original component-group +producer projection and PolyStore identity/optional-field decoding were read +semantically. This is complete source parse plus selected-family evidence, +not a full NRA/R1 detector or dynamic-resolution proof. No structural refactor +or production code change is made; no R0 improvement is claimed. + +The original project_knowledge_assets -> KnowledgeBaseService -> AgentSkillBundle +-> sync_skills owner chain passes1 focused control: source/package full bytes, +rendered whole viewer-QA/lifecycle content, full retirement subsection at the +original MAX_DOCUMENT_CHARS bound, search discovery, managed guide bytes and +unchanged second sync. Terminal0,9.69s whole invocation/7.21s pytest, +330708KiB/Swap0. The new assertion compares the COMPLETE source span with the +retrieved subsection; it does not match a phrase as behavioral proof. +Existing plugin-free asyncio-configuration warnings remain in raw output. +Skill-creator quick_validate reports Skill is valid, terminal0. The original +source bootstrap and source-byte-qualified tabular ABI backing were reused; +C++15acc82b8ab64268bd1ea4f83fa7a68f527bf317f002e9f39e15be321e03b28e +is unchanged. No new build/install, native execution or live managed-skill sync. + +Guide SHA256 bede1fa02bce04ed87ab31286327500df2771e8af3060db9f94cf43462acf4a7. +Byte-exact fifteen-member source/raw-log archive +viewer-retirement-mounted-routes-20261004.tar.gz is18762bytes, SHA256 +0fa36297a868602299f4fb6ca0e879d627f0eed9c7be278aa34f44b61e3fa32c; +tar --compare passed. First failed assertion, all original warnings and later +accepted outputs are preserved, not rewritten as clean evidence. Source guide, +test and verification caller are included; originals remain in the owned +validation/viewer-retirement-mounted-routes699 directory. Eight foreign +gitlinks and all earlier untracked ledgers are preserved, unstaged and unchanged. + This documentation change does not claim a new native retirement, selected geometry-survivor acceptance, autonomous gain or installed scientific update. Existing active/frozen author packages remain unchanged. CI deferred. diff --git a/docs/validation/viewer-retirement-mounted-routes-20261004.tar.gz b/docs/validation/viewer-retirement-mounted-routes-20261004.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..25aa2c8af9fcc05281539b314f21ac188faa39ae GIT binary patch literal 18762 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 literal 0 HcmV?d00001 diff --git a/tests/unit/agent/test_viewer_retirement_guide_projection.py b/tests/unit/agent/test_viewer_retirement_guide_projection.py index 3bbad91f42..3598bdc6f8 100644 --- a/tests/unit/agent/test_viewer_retirement_guide_projection.py +++ b/tests/unit/agent/test_viewer_retirement_guide_projection.py @@ -7,7 +7,7 @@ from openhcs.agent.dto.knowledge import KnowledgeBaseDocumentRequest, KnowledgeBaseSearchRequest from openhcs.agent.services.knowledge_base_service import ( - KnowledgeBaseService, load_document_specs_from_manifest, + MAX_DOCUMENT_CHARS, KnowledgeBaseService, load_document_specs_from_manifest, ) from openhcs.agent.skill_bundle import AGENT_PLUGIN_MANIFEST_PATH, AgentSkillBundle from openhcs.agent.skill_sync import sync_skills @@ -38,6 +38,17 @@ def test_real_viewer_guide_projection_retrieval_and_skill_delivery(tmp_path): # The original renderer joins source lines; compare all content, not a # wording substring that would pretend to prove the guide's decisions. assert reply.content == "\n".join((root / path).read_text().splitlines()) + if document_id == "openhcs_viewer_qa": + section = next(item for item in reply.sections + if item.section_id == "keep-iterative-review-within-its-resource-budget") + excerpt = service.get_document(KnowledgeBaseDocumentRequest.from_fields( + document_id=document_id, section_id=section.section_id, + max_chars=MAX_DOCUMENT_CHARS, + )) + assert not excerpt.errors and not excerpt.truncated + assert excerpt.content == "\n".join( + (root / path).read_text().splitlines()[section.start_line - 1:section.end_line] + ) paths.append(path) found = service.search(KnowledgeBaseSearchRequest(query="viewer layer retirement", limit=5)) assert any(hit.document.document_id == "openhcs_viewer_qa" for hit in found.hits)