zorya-classifier 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +11 -0
  3. package/README.md +127 -2
  4. package/dist/app/cli-route.d.ts +3 -0
  5. package/dist/app/cli-route.js +40 -0
  6. package/dist/app/create-classifier.d.ts +14 -0
  7. package/dist/app/create-classifier.js +100 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.js +33 -0
  10. package/dist/entities/contracts.d.ts +395 -0
  11. package/dist/entities/contracts.js +90 -0
  12. package/dist/entities/errors.d.ts +7 -0
  13. package/dist/entities/errors.js +16 -0
  14. package/dist/features/choice-beam-layout.d.ts +18 -0
  15. package/dist/features/choice-beam-layout.js +136 -0
  16. package/dist/features/choice.d.ts +4 -0
  17. package/dist/features/choice.js +83 -0
  18. package/dist/features/prompts.d.ts +8 -0
  19. package/dist/features/prompts.js +56 -0
  20. package/dist/features/uniform-grid.d.ts +3 -0
  21. package/dist/features/uniform-grid.js +35 -0
  22. package/dist/index.d.ts +5 -0
  23. package/dist/index.js +2 -0
  24. package/dist/infrastructure/openrouter-common.d.ts +130 -0
  25. package/dist/infrastructure/openrouter-common.js +317 -0
  26. package/dist/infrastructure/openrouter-vision.d.ts +8 -0
  27. package/dist/infrastructure/openrouter-vision.js +12 -0
  28. package/dist/infrastructure/openrouter.d.ts +19 -0
  29. package/dist/infrastructure/openrouter.js +207 -0
  30. package/dist/infrastructure/raster.d.ts +2 -0
  31. package/dist/infrastructure/raster.js +121 -0
  32. package/dist/infrastructure/vision-chat.d.ts +64 -0
  33. package/dist/infrastructure/vision-chat.js +309 -0
  34. package/dist/openai-compatible.d.ts +5 -0
  35. package/dist/openai-compatible.js +7 -0
  36. package/dist/openrouter.d.ts +4 -0
  37. package/dist/openrouter.js +2 -0
  38. package/dist/processes/classify.d.ts +2 -0
  39. package/dist/processes/classify.js +21 -0
  40. package/dist/processes/locate.d.ts +2 -0
  41. package/dist/processes/locate.js +201 -0
  42. package/dist/shared/choice-mass.d.ts +2 -0
  43. package/dist/shared/choice-mass.js +19 -0
  44. package/dist/shared/gate.d.ts +11 -0
  45. package/dist/shared/gate.js +52 -0
  46. package/dist/shared/scope.d.ts +12 -0
  47. package/dist/shared/scope.js +29 -0
  48. package/docs/README.ru.md +245 -0
  49. package/docs/acceptance.md +31 -0
  50. package/docs/api.md +45 -0
  51. package/docs/architecture.md +32 -0
  52. package/docs/benchmarks.md +53 -0
  53. package/docs/evidence/current-linux-check.json +15 -0
  54. package/docs/evidence/decisions-completion-v1-manifest.json +96 -0
  55. package/docs/evidence/decisions-completion-v1-report.json +1205 -0
  56. package/docs/evidence/decisions-selection-v1-manifest.json +96 -0
  57. package/docs/evidence/decisions-selection-v1-report.json +1457 -0
  58. package/docs/evidence/jev-pricing-2026-10-18.json +69 -0
  59. package/docs/evidence/linux-check.json +20 -0
  60. package/docs/evidence/linux-check.txt +205 -0
  61. package/docs/evidence/live-release-smoke-manifest.json +82 -0
  62. package/docs/evidence/live-release-smoke-provenance.json +9 -0
  63. package/docs/evidence/live-release-smoke-report.json +2136 -0
  64. package/docs/evidence/live-v1-manifest.json +84 -0
  65. package/docs/evidence/live-v1-provenance.json +9 -0
  66. package/docs/evidence/live-v1-report.json +15555 -0
  67. package/docs/evidence/luna-decisions-fine-probe.json +19 -0
  68. package/docs/evidence/luna-decisions-locator-smoke-manifest.json +39 -0
  69. package/docs/evidence/luna-decisions-locator-smoke-report.json +149 -0
  70. package/docs/evidence/pack-check.json +26 -0
  71. package/docs/evidence/protocol-probes.json +61 -0
  72. package/docs/evidence/rejected-vision-selection-v1-qwen-photo-dev-01.json +42 -0
  73. package/docs/evidence/rejected-vision-selection-v1-qwen-photo-dev-17.json +42 -0
  74. package/docs/evidence/rejected-vision-selection-v1-qwen-photo-heldout-09.json +42 -0
  75. package/docs/evidence/rejected-vision-selection-v2-haiku-photo-dev-16.json +42 -0
  76. package/docs/evidence/rejected-vision-selection-v2-haiku-support-heldout-016.json +42 -0
  77. package/docs/evidence/vision-cost-reconciliation.json +37 -0
  78. package/docs/evidence/vision-model-summary.json +562 -0
  79. package/docs/evidence/vision-selection-v1-manifest.json +95 -0
  80. package/docs/evidence/vision-selection-v1-report.json +4598 -0
  81. package/docs/evidence/vision-selection-v2-manifest.json +95 -0
  82. package/docs/evidence/vision-selection-v2-report.json +1139 -0
  83. package/docs/evidence/windows-native.json +73 -0
  84. package/docs/evidence/windows-secrets.json +46 -0
  85. package/docs/operations.md +15 -0
  86. package/docs/plan.md +25 -0
  87. package/docs/provenance.json +32 -0
  88. package/docs/publishing.md +21 -0
  89. package/docs/results.md +69 -0
  90. package/docs/vision-results.md +51 -0
  91. package/package.json +89 -4
@@ -0,0 +1,73 @@
1
+ {
2
+ "status": "PASS",
3
+ "scope": "Final explicit-rounding runtime native Windows source/package offline qualification; no inference, game, app or installer",
4
+ "createdAt": "2026-10-17T21:47:43.642962+00:00",
5
+ "rawReceiptSha256": "86f9d51e043883e7e8f7c804f6ef64037d84adb548fedc8b121be8a79298df49",
6
+ "platform": {
7
+ "platform": "win32",
8
+ "node": "v24.19.0",
9
+ "arch": "x64",
10
+ "osType": "Windows_NT",
11
+ "osRelease": "10.0.26200",
12
+ "osVersion": "Windows 11 Pro"
13
+ },
14
+ "npm": "11.17.0",
15
+ "steps": [
16
+ {
17
+ "step": "check-final",
18
+ "durationMs": 11737.6716,
19
+ "exitCode": 0,
20
+ "timedOut": false,
21
+ "physicalCloseObserved": true,
22
+ "stdoutSha256": "1a02d2081e7b52e7d16c252627caa7d2427aaf93c5defc2aea541b18c86487e7",
23
+ "stderrSha256": "bdd8e52cff96a1a2de65f7c89c275f8eb847c4cb3c4e80298775e92dc8853ba8"
24
+ },
25
+ {
26
+ "step": "pack-check-final",
27
+ "durationMs": 6953.8477,
28
+ "exitCode": 0,
29
+ "timedOut": false,
30
+ "physicalCloseObserved": true,
31
+ "stdoutSha256": "975c81cf847d6360b2199e518f17f84e2570210a46e4759409f8ec319f57fdcc",
32
+ "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
33
+ }
34
+ ],
35
+ "tests": {
36
+ "tests": 142,
37
+ "pass": 142,
38
+ "fail": 0,
39
+ "cancelled": 0,
40
+ "skipped": 0
41
+ },
42
+ "consumer": {
43
+ "independentConsumer": "passed",
44
+ "declarations": "compiled",
45
+ "sharp": "0.34.5",
46
+ "vips": "8.17.3",
47
+ "classification": "yes",
48
+ "localization": "located",
49
+ "controlledDecisionCalls": 4,
50
+ "providerHttpCalls": 0
51
+ },
52
+ "testedSnapshotPackage": {
53
+ "files": 47,
54
+ "unpackedSize": 109715,
55
+ "sha256": "9029ed25c0c5f2ecc638d87d69d0dbefe1024181ccbe19bfe6f5513e85da0426",
56
+ "runtimeDistFiles": 34,
57
+ "runtimeDistSha256": "62d5a0075e5ccca6627ba81f8ca8be427f499ded7508570171c00520bcf369ca",
58
+ "consumerDeclarationFiles": 184,
59
+ "npmTransport": "node npm-cli.js; shell:false"
60
+ },
61
+ "runtimeDistEqualLinuxWindows": true,
62
+ "sourceMismatchCounts": {
63
+ "immutable": 0,
64
+ "staged": 0
65
+ },
66
+ "limitations": [
67
+ "Offline fake-fetch/DecisionPort checks do not qualify live Jev accuracy or performance",
68
+ "No Windows app/installer/game executed",
69
+ "Source docs may evolve after this immutable runtime snapshot",
70
+ "No OS-wide process/network trace claimed"
71
+ ],
72
+ "note": "Host-specific temporary paths removed from this public summary; original receipt retained locally. Final release docs/evidence can change archive SHA without changing tested dist."
73
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "status": "PASS",
3
+ "scope": "Native Windows offline secrets guard qualification only; not a repeat of runtime suite",
4
+ "createdAt": "2026-10-17T22:05:25.617601+00:00",
5
+ "probe": {
6
+ "node": "v24.19.0",
7
+ "arch": "x64",
8
+ "platform": "win32",
9
+ "osRelease": "10.0.26200",
10
+ "osVersion": "Windows 11 Pro"
11
+ },
12
+ "gitVersion": "git version 2.52.0.windows.1",
13
+ "tests": {
14
+ "tests": 16,
15
+ "pass": 15,
16
+ "fail": 0,
17
+ "cancelled": 0,
18
+ "skipped": 1
19
+ },
20
+ "expectedSkipped": "POSIX FIFO creation regression; unavailable on Win32; Linux passed this case",
21
+ "worktreeScan": {
22
+ "status": "PASS",
23
+ "mode": "--worktree",
24
+ "scanned": 5,
25
+ "skippedBinary": 0,
26
+ "totalBytes": 154472
27
+ },
28
+ "stagedScan": {
29
+ "status": "PASS",
30
+ "mode": "--staged",
31
+ "scanned": 5,
32
+ "skippedBinary": 0,
33
+ "totalBytes": 154472
34
+ },
35
+ "sourceGuardPinsUnchanged": true,
36
+ "stagedPinsUnchanged": true,
37
+ "otherSourceChanges": [],
38
+ "limitations": [
39
+ "Heuristic text scanner does not guarantee detection of all credentials",
40
+ "Binary contents skipped explicitly after filename checks",
41
+ "Parent-directory replacement is not an atomic filesystem sandbox boundary",
42
+ "No model HTTP, private-key modification, application or installer execution",
43
+ "Npm registry installation used pinned lock and --ignore-scripts; no OS-wide network trace"
44
+ ],
45
+ "rawReceiptSha256": "271c48e4f6f149b195fd6e8c6d385d69f11bd41764cfa4ff52ce2a0b0ff9eaea"
46
+ }
@@ -0,0 +1,15 @@
1
+ # Operations
2
+
3
+ Configure a trusted model endpoint or the optional OpenRouter route. SDK factories receive endpoint/model/key explicitly; the core knows only DecisionPort. Keep server-specific credentials separate from OpenRouter credentials. Store keys in ignored local files or a secret manager. No startup request is made.
4
+
5
+ CLI requires `ZORYA_MODEL` and defaults to `ZORYA_MODE=decisions`. For ordinary vision models/custom chat servers choose `ZORYA_MODE=chat`. OpenRouter mode requires `OPENROUTER_API_KEY` and `ZORYA_PROVIDER`; direct mode uses a full `ZORYA_ENDPOINT` with optional separate `ZORYA_API_KEY`, and never forwards the OpenRouter key. In chat mode, optional `ZORYA_REASONING_EFFORT` and `ZORYA_RESPONSE_FORMAT` must be supported by the chosen endpoint. Use `zorya-classifier --help`. Commands: classify-text text classes.json; classify-image image classes.json; locate image target. CLI calls real paid models. Native images are decoded locally through Sharp; external requests send prepared text/images to the configured route. The library neither writes nor logs media by default.
6
+
7
+ Choose a finite timeout based on your UI needs. Default 45s includes queue time; no latency SLA is asserted. Handle CAPACITY by applying upstream backpressure rather than creating more clients. Explicitly cancel superseded application requests and call dispose on shutdown. A cancelled native job may finish before its slot is released; this prevents unbounded physical concurrency.
8
+
9
+ Unknown cost remains unknown. Budget your own calls or use the benchmark's conservative reservations. Do not implement retries around locate without accounting for all prior physical calls and potential charges. Screenshots can become stale while analysis runs; acquiring current frames and deciding whether results are still relevant belongs to the application.
10
+
11
+ Build release locally with npm run check and npm run pack:check. Produce npm pack only after those gates. Review LICENSE/NOTICE/acceptance and archive contents before publishing. Publication destinations are GitHub `zoomplus/zorya-classifier` and npm `zorya-classifier` under owner `zoomplus`. Authentication stays outside the repository. Check the remote release/registry and external receipt for actual publication state.
12
+
13
+ Owner handoff and authentication steps are in [publishing](publishing.md). Secret scanning commands and their limits are in [SECURITY](../SECURITY.md); they run in Husky, source checks and the archive check. Release manifests live next to the prepared archives, outside Git/npm contents.
14
+
15
+ Compatibility with another image-capable model does not imply tested accuracy or support for all structured-output parameters. Choose prompt/JSON-object/JSON-schema mode according to server capabilities, inspect explicit failures and consult docs/vision-results.md. Never label generated ranks as calibrated probabilities.
package/docs/plan.md ADDED
@@ -0,0 +1,25 @@
1
+ # Accepted open-source extraction plan
2
+
3
+ First deliver an independent MIT Node.js/TypeScript library with classify(text/image/both) and locate(image,target), powered by Jev 1.14/TypeSafe. Preserve three Choice stages for localization, stable maxima/ties and source coordinates; no implicit model/provider fallback or retries. Classification is one native Choice. Separate heavy optional refinement and game/application dependencies.
4
+
5
+ Prepare public contracts, strict schemas, source rules, architecture/API/operations documentation, examples/CLI, offline regressions and Windows/Linux CI. Package into a clean npm archive and test installation outside the repository. Scan release contents for secrets, private paths and unwanted assets. Prepare a clean source repository; public GitHub/npm publishing is a separate action.
6
+
7
+ Evaluate 60 licensed real photographs (20 development/40 heldout) and 30 authored text fixtures (10/20). Separate raw producer inputs from ground truth. Compare classification against an independently called identical native Choice; evaluate one/two-stage locator prefix ablations from the three-stage run. Record mistakes, errors, latency, costs, true unknowns and visual overlays. No universal superiority claim without evidence.
8
+
9
+ Acceptance requires executed source checks, clean independent consumer install, an honest real-provider report and complete release documentation. Configured CI is not evidence of execution. Historical gaming/microphone checks and installer work remain separate.
10
+
11
+ ## Owner revision: universal vision classification before first npm publication
12
+
13
+ The owner replaced the Jev-centered release design after initial GitHub creation and before npm publication. Ordinary image-capable language models must work without a native classification/Decisions API. Implement an OpenRouter chat-completions adapter that requests closed ranked IDs and explicit present/absent/unknown predicates, validates all outputs and rejects invented IDs, extra questions, truncation, refusals and malformed JSON. Do not manufacture probabilities from ranks. Keep the original native adapter only as an optional compatibility/benchmark integration, never an implicit dependency/fallback.
14
+
15
+ Preserve the three grid stages, source-pixel geometry, input ownership, bounded queues, cancellation, byte caps, no retries/model fallback and route accountability. Extend the internal/public result contract with explicit rank-only evidence. The selected class is the first ranked ID; only genuine provider probability distributions remain probability-valued. Update examples, CLI, docs and rules to the generic adapter.
16
+
17
+ Compare cheap general vision candidates under a newly authorized bounded paid run before recommending the cheapest tested route that meets the recorded baseline. Preserve historical Jev reports as historical evidence, not a qualification for a different backend. A pending separate paid-run request does not authorize dispatch until approved. npm publication waits for updated code, independent archive checks, Windows/Linux CI and honest current-model evidence.
18
+
19
+ The first hosted Windows CI exposed a temporary-directory alias problem in the declaration-isolation check. Resolve Windows 8.3 aliases with the native filesystem canonicalizer; do not broaden allowed declaration roots or skip archive verification. Preserve the failed run and verify the corrected check in hosted Windows CI.
20
+
21
+ Additional owner requirement: provide a direct OpenAI-compatible endpoint adapter (including anonymous local servers/custom authentication) and a public custom port. OpenRouter is optional. README must explicitly distinguish configurable vision-model support from models/routes actually tested, with per-model accuracy, error, latency and price data.
22
+
23
+ ## Latest owner priority: native decision models except Jev
24
+
25
+ Prioritize Luna Decisions through the typed Decisions API. Keep model/provider explicit and implement a generic native adapter; retain ordinary vision-chat support as an alternative, and Jev only as an optional historical integration. Do not silently fall back between protocols. Native probabilities remain genuine values; quantization assumptions require explicit model-specific evidence/configuration. Reallocate the remaining approved comparison budget without exceeding290 total calls/$0.50. Current ordinary runs and their failures remain preserved.
@@ -0,0 +1,32 @@
1
+ {
2
+ "upstreamCommit": "97fca38ef027f0c83c63bd069248e6299619abd2",
3
+ "algorithm": "coarse4x4 -> four padded regions/fine<=49 each -> four enlarged candidate Choice",
4
+ "copiedOrAdaptedFiles": [
5
+ {
6
+ "source": "packages/screen-locator-service/src/features/grid/uniform-grid.ts",
7
+ "sourceSha256": "c4ed5506218e93a79eade528942fdc35f9197b2ea5f1af2027cba21b6e18b847",
8
+ "destination": "src/features/uniform-grid.ts"
9
+ },
10
+ {
11
+ "source": "packages/screen-locator-service/src/features/grid/choice-beam-layout.ts",
12
+ "sourceSha256": "4a2a22efc43ef69313da5cacb41425c336186e8602fb168dfdef5572586ee6c8",
13
+ "destination": "src/features/choice-beam-layout.ts"
14
+ },
15
+ {
16
+ "source": "tools/eslint-plugin-element-guard/no-discarded-interval.js",
17
+ "sourceSha256": "321c43b61b673515571c969ba4ff75e307c0eefaccad308c414c5736174d260e",
18
+ "destination": "tools/no-discarded-interval.mjs"
19
+ }
20
+ ],
21
+ "changes": [
22
+ "Standalone ports and lifecycle; no game/application dependencies",
23
+ "Multiple targets allowed, returning one candidate",
24
+ "Stable supplied-order tie selection",
25
+ "Compact grid rendering and generic prompts require independent new quality evidence",
26
+ "45-second default for standalone operations; original gaming deadline unchanged",
27
+ "Provider-independent ordinary vision chat protocol with closed ranks and separate presence; no invented probabilities",
28
+ "Direct OpenAI-compatible endpoint and optional OpenRouter wrapper; native Jev retained as optional historical integration",
29
+ "One winner for single-label/final selection; four ranks only for coarse/fine beam stages"
30
+ ],
31
+ "originalRepositoryModified": false
32
+ }
@@ -0,0 +1,21 @@
1
+ # Publishing handoff
2
+
3
+ The owner has authorized publication under GitHub account `zoomplus` and npm account `zoomplus`. The selected destinations are the public repository `zoomplus/zorya-classifier` and public package `zorya-classifier`. These names were available at the preflight check. Check the actual repository/registry and release receipt for completion; this document describes the release process rather than asserting remote state.
4
+
5
+ ## Owner and authentication
6
+
7
+ The supplied account profiles are https://github.com/zoomplus and https://www.npmjs.com/~zoomplus. The owner requested creation of the repository and publication without manually preparing either destination. MIT was already selected for the extracted code. No private email address is added to package metadata. A local package name is not a registry reservation; recheck availability and identity before dispatch.
8
+
9
+ Send account names and URLs, not passwords, API keys, recovery codes or authentication files. GitHub can be authenticated locally with `gh auth login --web`; the owner completes the browser flow. npm can use local `npm login` followed by the required browser/2FA publication confirmation. See [GitHub CLI authentication](https://cli.github.com/manual/gh_auth_login) and [npm publication authentication](https://docs.npmjs.com/requiring-2fa-for-package-publishing-and-settings-modification/).
10
+
11
+ For later CI releases, configure [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/) with the actual GitHub repository/workflow. It uses OIDC rather than a long-lived npm token. Configure this after the package ownership and repository are known; a generic workflow would otherwise name an invented owner. Do not place tokens in a workflow or issue.
12
+
13
+ ## Maintainer release sequence
14
+
15
+ 1. Recheck package-name availability, author rights, MIT/third-party notices, acceptance limits and the desired public destination.
16
+ 2. Set the final package name/scope and repository/homepage/bugs metadata. Update imports/examples if the name changes, then rerun source and installed-archive checks. Existing archive hashes apply only to the original name/content.
17
+ 3. Run `npm run check`, `npm run pack:check`, `npm run format:check` and a redacted independent secret scan. Inspect actual staged blobs and the produced archive, not only `.gitignore`.
18
+ 4. Create/push only the clean standalone history, enable secret scanning/push protection and inspect the CI matrix. Raw runs, environment files, personal media and upstream history stay local. Public corpus downloads retain source licenses.
19
+ 5. Pack the reviewed version, verify its SHA256, then publish with the authorized account. Require the owner's authentication confirmation when prompted. Record registry integrity, Git tag/commit and release evidence.
20
+
21
+ GitHub is sufficient to share source and accept contributions. npm is optional, but makes installation and versioned dependency management easier. The existing local archive can already be installed without either publication.
@@ -0,0 +1,69 @@
1
+ # Recorded model results
2
+
3
+ This report is historical evidence for the optional Jev integration. Current native Luna Decisions and ordinary vision model comparisons are in [tested models](vision-results.md); these figures do not qualify a different backend.
4
+
5
+ These are measured outcomes, including mistakes and failures. They are not a claim that the wrapper improves Jev's classification accuracy, that photographic accuracy transfers to games, or that a selected cell is a segmented object.
6
+
7
+ ## Full corpus: live-v1
8
+
9
+ The run completed on 2026-10-17 UTC with the source hashes in the [manifest](evidence/live-v1-manifest.json). It used the original strict probability-sum validator. The [complete report](evidence/live-v1-report.json) retains every sample, split, error, timing and joined ground-truth result. Corpus preparation and attribution are described in [benchmarks](benchmarks.md).
10
+
11
+ The corpus contains 60 licensed photographs (20 dev / 40 heldout; 25 requested object classes) and 30 authored text-intent fixtures (10 dev / 20 heldout). The text fixtures are not real customer conversations. Public heldout can overlap provider training; it was only held out from local development. There was no independent human re-annotation or perceptual duplicate audit.
12
+
13
+ | Classification | Library | Independent native Jev Choice |
14
+ | --------------------- | --------------- | ----------------------------- |
15
+ | Photographs correct | 55/60 (91.67%) | 55/60 (91.67%) |
16
+ | Photograph macro-F1 | 0.84367 | 0.84367 |
17
+ | Text fixtures correct | 30/30 | 30/30 |
18
+ | Photograph p50 / p95 | 2.835 / 4.287 s | 2.615 / 3.804 s |
19
+ | Text p50 / p95 | 0.283 / 0.323 s | 0.293 / 0.333 s |
20
+
21
+ Photo presence classification: TP 48, FN 2, TN 7, FP 3. Dev 18/20, heldout 37/40. Text dev 10/10, heldout 20/20. The chosen class agreed across all 90 library/native pairs. The native baseline makes a separate provider call with an identical request; it is not a copied answer. Values can vary between calls.
22
+
23
+ ## Locator and stage trade-off
24
+
25
+ A positive hit means the **selected cell's center** lies in at least one annotated bounding box. This evaluates an area hypothesis, not the object's center or segmentation; a source bounding box can include background. Multiple matching instances are allowed. Prefix results reuse the same stage answers and are correlated ablations without the final candidate check.
26
+
27
+ | Metric | First-stage prefix | Two-stage prefix | Full three stages |
28
+ | --------------------------------------- | ------------------ | ----------------- | ----------------- |
29
+ | Successful, including correct negatives | 46/60 | 31/60 | 27/60 |
30
+ | Hits over all positive photos | 39/50 | 24/50 | 20/50 |
31
+ | Protocol failures | 1 | 22 | 23 |
32
+ | Unknown outcomes | 0 | 0 | 7 |
33
+ | False coordinates on absent targets | 3/10 | 2/10 | 1/10 |
34
+ | p50 / p95 | 5.189 / 7.437 s | 11.654 / 18.930 s | 13.642 / 22.229 s |
35
+ | Median selected image-area fraction | 6.25% | 0.418% | 0.513% |
36
+
37
+ For the full locator, 20 of 21 returned regions on positive photos hit a reference box. That conditional 95.24% excludes failures and abstentions; the result over **all 50 positives is 20/50**. Do not market the conditional percentage as overall accuracy. A larger first-stage region can achieve easier containment and does not offer the same spatial granularity.
38
+
39
+ | Stratum (10 photos each) | Classification correct | First stage success | Two stages | Three stages |
40
+ | ------------------------ | ---------------------- | ------------------- | ---------- | ------------ |
41
+ | Baseline | 9 | 10 | 4 | 2 |
42
+ | Repeated instances | 9 | 9 | 6 | 5 |
43
+ | Edge truncation | 10 | 9 | 8 | 7 |
44
+ | Absent target | 7 | 7 | 7 | 7 |
45
+ | Occlusion | 10 | 8 | 4 | 3 |
46
+ | Small target | 10 | 3 | 2 | 3 |
47
+
48
+ ## Protocol correction and final smoke
49
+
50
+ All 321 full-run HTTP responses were 200, with no timeouts. The strict adapter rejected 23 answers (`INVALID_RESPONSE`: stage 1 = 1, stage 2 = 21, stage 3 = 1). Their original raw rejected bodies were not saved. Therefore the cause of every rejection cannot be established retrospectively.
51
+
52
+ Two later diagnostic calls on saved request inputs produced one 153-option response whose 0.01-rounded values sum to 0.99, and one valid five-option response. They are new independent responses, not recovered original failures. The final adapter preserves raw scores and accepts only explicitly annotated quantization whose half-step intervals admit unit probability mass. No prompts, crops, rankings or geometry were changed. The exact 153-option response is covered by a regression. See [API](api.md) and [probe evidence](evidence/protocol-probes.json).
53
+
54
+ The final corrected runtime then completed a separate [smoke run](evidence/live-release-smoke-report.json): 2 dev photos + 2 dev texts, 14 HTTP calls, zero protocol failures. Photo classification was 1/2 for both library/native, texts 2/2 for both; localization returned one valid box hit and one `unknown`. This checks the corrected integration, **not a new full-corpus accuracy estimate**. The old failures remain unchanged. A full final-version quality benchmark remains future work within an explicitly funded run.
55
+
56
+ ## Calls, route and cost
57
+
58
+ | Run | HTTP calls | Known reported cost | Calls with unknown cost |
59
+ | ----------------- | ---------- | ------------------- | ----------------------- |
60
+ | Full live-v1 | 321 | $0.073546662 | 23 |
61
+ | Diagnostic probes | 2 | $0.001420734 | 0 |
62
+ | Final smoke | 14 | $0.004080510 | 0 |
63
+ | Total | 337 | $0.079047906 | 23 |
64
+
65
+ Adding the local $0.02 reservation for each unknown-cost call gives accounted exposure **$0.539047906**, not the actual final provider bill. The aggregate remains within the authorized 360-call / $1 diagnostic envelope. Local reservations do not enforce an account-wide spending cap.
66
+
67
+ The 298 accepted full-run responses and all 14 smoke responses report `typesafe/jev-1.14-20261014` / TypeSafe; the adapter requests `typesafe/jev-1.14`, only TypeSafe, without fallback/retry. The two probes also used the fixed route. Missing metadata is never silently assumed to prove routing or zero cost. Pricing was checked against the [dated primary-source snapshot](evidence/jev-pricing-2026-10-18.json).
68
+
69
+ Latencies include image preparation and benchmark artifact writes; measurements of the HTTP response headers alone are stored separately. They are not a service-level guarantee or evidence of sub-second localization.
@@ -0,0 +1,51 @@
1
+ # Tested models and results
2
+
3
+ Native decision models other than Jev are the primary integration. **Luna Decisions is the selected route:** it matched the historical photo/text counts on this corpus, while ordinary vision chat models remain configurable alternatives. This is an observed result on a small public corpus, not a statistical non-inferiority or universal-accuracy guarantee.
4
+
5
+ The fixed corpus has60 licensed photos (20 development/40 heldout) and30 authored text fixtures (10/20). Ground truth never enters model requests. Errors stay in the accuracy denominator; unstarted cases remain unverified. Public images may overlap model training. Exact [summaries/source pins](evidence/vision-model-summary.json) and individual run reports below retain failures.
6
+
7
+ | Model / route | API | Photos | Heldout photos | Texts | Protocol/provider errors |
8
+ | ---------------------------------------- | ------------------------- | ------ | -------------- | ----- | ------------------------ |
9
+ | `openai/gpt-6-luna-decisions · openai` | Decisions | 55/60 | 39/40 | 30/30 | 0 |
10
+ | `openai/gpt-6-luna · openai` | Chat | 54/60 | 38/40 | 30/30 | 1 |
11
+ | `qwen/qwen3.7-flash · alibaba` | Chat | 53/60 | 37/40 | 26/30 | 3 |
12
+ | `anthropic/claude-haiku-5.5 · anthropic` | Chat, stopped photo batch | 11/16 | 0/0 | 29/30 | 3 |
13
+ | `nex-agi/nex-n2.5-mini · nex-agi/bf16` | Chat screening | 6/10 | 0/0 | 0/0 | 0 |
14
+
15
+ The legacy Jev result was55/60 photos,37/40 heldout and30/30 texts; it remains in the [historical report](results.md). Jev is excluded from the new recommendation by owner preference. Luna Decisions produced55/60,39/40 heldout and30/30 texts with zero classification protocol/provider errors. Among the fully tested non-Jev routes, it alone met the recorded photo/text target. Lower-cost Qwen did not retain that accuracy; Nex received only a10-photo development screen. Haiku stopped its photo batch after two consecutive errors, leaving44 photos unverified.
16
+
17
+ ## Latency and reported cost
18
+
19
+ End-to-end per-operation latency includes preparation, network and provider processing. Quantiles use nearest rank, include failed attempts and describe this one run; they are not a service SLA. Cost below covers validated classification metadata only, with rejected-response billing reconciliation described separately.
20
+
21
+ | Route | Photo p50 / p95 | Text p50 / p95 | Known classification cost |
22
+ | -------------- | --------------- | -------------- | ------------------------- |
23
+ | luna-decisions | 1.43s / 3.44s | 0.22s / 0.41s | $0.00793950 |
24
+ | luna | 3.20s / 4.79s | 0.96s / 1.26s | $0.01314735 |
25
+ | qwen | 3.94s / 5.32s | 1.10s / 1.25s | $0.00330488 |
26
+ | haiku | 3.09s / 4.19s | 0.76s / 1.00s | $0.00719360 |
27
+ | nex | 1.60s / 3.90s | — / — | $0.00030315 |
28
+
29
+ The [Luna Decisions catalog](https://openrouter.ai/openai/gpt-6-luna-decisions) listed$0.10/M input tokens and free output on2026-10-18. Exact route receipts take precedence over a catalog floor. The90 native classification calls reported$0.00793950 total. Do not infer this price for a different image size, route, provider or future date.
30
+
31
+ ## Protocol variants and failures
32
+
33
+ The first chat comparison requested two/four ranked IDs even for single-label classification. Qwen returned only one ID on three photos and failed that old contract; those failures remain failures. The revised adapter requests exactly one classification/final ID and four only for spatial beam stages. Haiku used this revised protocol and had one authentication/provider rejection and two non-JSON answers. These are different protocol snapshots and not a controlled paired prompt experiment. Luna Decisions uses actual typed Choice probabilities and Noul; it never parses a generated chat ranking and does not inherit Jev-specific rounding.
34
+
35
+ Native Luna was evaluated in two disjoint sessions:40 heldout photos+10 development texts, then the missing20 development photos+20 heldout texts. No classification was replayed, relabeled or prompt-tuned between them. The inference source is unchanged across those sessions; their manifests pin it. The mutable budget initialization was refactored after the second snapshot to satisfy the race lint rule, without changing inference.
36
+
37
+ [Chat v1](evidence/vision-selection-v1-report.json) · [Chat v2](evidence/vision-selection-v2-report.json) · [Native first session](evidence/decisions-selection-v1-report.json) · [Native completion](evidence/decisions-completion-v1-report.json).
38
+
39
+ ## Localization remains experimental
40
+
41
+ The first native locator smoke reached its fine stage but received a provider error. An explicit diagnostic replay of that exact195-option/nine-image fine request returned HTTP502: `OpenAI refused to answer question "selection"`. The [diagnostic receipt](evidence/luna-decisions-fine-probe.json) is preserved. This does not establish a documented universal option/image limit or authorize silently changing geometry; model refusal stays an error. A subsequent fixed flower-image smoke completed all three native stages in4.75s and returned a region; its [report](evidence/luna-decisions-locator-smoke-report.json) includes the reference-box metric. This one success does not erase the failed request or qualify the whole locator corpus. A valid classification result does not guarantee locator compatibility.
42
+
43
+ The grid pipeline returns a hypothesized region, never a segmentation mask, tight box or object center. No map/minimap, universal localization or sub-second claim is made. Offline three-stage fixtures verify geometry/lifecycle only.
44
+
45
+ ## Model and provider choice
46
+
47
+ The core depends only on `DecisionPort`. Use `createOpenRouterDecisions` for compatible typed native models, `createOpenRouterVision` for ordinary vision chat, or `createOpenAICompatibleVision` for trusted direct providers/local servers. Another native wire protocol can implement the public port. No adapter automatically changes the model/provider/protocol. These live results used OpenRouter as transport; a real local HTTP fixture separately verified direct chat protocol without a key or router fields, not a local model's factual accuracy.
48
+
49
+ A model must support its chosen API and modalities, follow the requested closed task and satisfy response validation. `classify` uses at most one image; `locate` needs up to nine. Untested models are configurable, not automatically qualified.
50
+
51
+ The completed comparison used332 requests against the expanded1000-call ceiling. Reported known cost is$0.03456876; four calls retain unknown costs. With$0.05 reservations each, accounted exposure is$0.23456876 within the$0.50 admission cap. The five rejected-chat receipts were reconciled for billing only; no accuracy failures were repaired. This accounting is separate from the historical Jev benchmark and is not an account invoice.
package/package.json CHANGED
@@ -1,6 +1,91 @@
1
1
  {
2
2
  "name": "zorya-classifier",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Provider-independent text/image classification and coarse-to-fine object localization for Node.js",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=22.12.0"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "./openrouter": {
16
+ "types": "./dist/openrouter.d.ts",
17
+ "import": "./dist/openrouter.js"
18
+ },
19
+ "./openai-compatible": {
20
+ "types": "./dist/openai-compatible.d.ts",
21
+ "import": "./dist/openai-compatible.js"
22
+ }
23
+ },
24
+ "bin": {
25
+ "zorya-classifier": "./dist/cli.js"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE",
31
+ "NOTICE.md",
32
+ "docs"
33
+ ],
34
+ "sideEffects": false,
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "typecheck": "tsc --noEmit",
38
+ "lint": "eslint . --max-warnings 0",
39
+ "format": "prettier --write .",
40
+ "format:check": "prettier --check .",
41
+ "test": "node --import tsx --test --test-concurrency=2 test/*.test.ts",
42
+ "check": "npm run secrets:check && npm run typecheck && npm run lint && npm run boundaries && npm run dead-code:ci && npm test && npm run build",
43
+ "boundaries": "node scripts/boundaries.mjs",
44
+ "dead-code:ci": "knip --no-progress",
45
+ "pack:check": "node scripts/pack-check.mjs",
46
+ "prepare": "husky",
47
+ "secrets:check": "node scripts/secrets.mjs --worktree",
48
+ "secrets:staged": "node scripts/secrets.mjs --staged",
49
+ "prepublishOnly": "npm run check && npm run pack:check"
50
+ },
51
+ "dependencies": {
52
+ "sharp": "0.34.5",
53
+ "zod": "3.25.76"
54
+ },
55
+ "devDependencies": {
56
+ "@eslint/js": "9.39.5",
57
+ "@types/node": "24.3.0",
58
+ "eslint": "9.39.5",
59
+ "eslint-plugin-promise": "7.3.0",
60
+ "eslint-plugin-unicorn": "59.0.1",
61
+ "husky": "9.1.7",
62
+ "knip": "5.62.0",
63
+ "prettier": "3.6.2",
64
+ "tsx": "4.20.5",
65
+ "typescript": "5.9.2",
66
+ "typescript-eslint": "8.71.1"
67
+ },
68
+ "author": "zoomplus",
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "git+https://github.com/zoomplus/zorya-classifier.git"
72
+ },
73
+ "homepage": "https://github.com/zoomplus/zorya-classifier#readme",
74
+ "bugs": {
75
+ "url": "https://github.com/zoomplus/zorya-classifier/issues"
76
+ },
77
+ "keywords": [
78
+ "classification",
79
+ "image-classification",
80
+ "object-localization",
81
+ "openrouter",
82
+ "typescript",
83
+ "vision",
84
+ "openai-compatible",
85
+ "multimodal"
86
+ ],
87
+ "publishConfig": {
88
+ "access": "public",
89
+ "registry": "https://registry.npmjs.org/"
90
+ }
91
+ }