Our vision model accepted a printed hazelnut at 97% confidence. One rule, recalled through Hindsight, changed the answer on the same photo. This is how we built SpecLens, and what that result does and does not prove.
By Aditya Arnav and Pallab Das, team Vulcan.
The numbers (one recorded run, Nov 7, 2026)
- 0.97 and 0.82: the model's confidence on the wrong accept and the right reject of the same photo.
- 3/4 to 4/4: correct decisions without memory and with it, on four synthetic cases.
- 0 of 2: untouched parts rejected, with memory off and with memory on.
- 304 pixels: how much of a 1024 x 1024 image the faint print changed.
Four rules
- The correction outlives the inspection. SQLite saves it first, and the model's original verdict stays on record.
- Every recalled fact needs a source. A fact with no synced correction behind it never reaches the prompt.
- Memory follows the specification. Each factory, part family and revision gets its own Hindsight bank.
- A failed recall stops the run. An outage can't pass as a clean inspection.
The B2 photo: two answers from one model
Our vision model looked at a hazelnut, reported 97% confidence, and accepted it.
"Whole in-shell hazelnut shows only natural shell colour variation, longitudinal stripes and gloss," it wrote. "No drilled hole, fracture/crack, straight-edged cut, or ink/print marking observed."
The shell carried the characters B2 in faint white ink.
We sent the same photo to the same model with the same specification. The only new input was one written rule, recalled from Hindsight. The model rejected the part this time and named the correction it had applied.
Same photo, same model, same specification. Only the recalled rule changed.
That pair of answers is why Pallab Das and I built SpecLens around agent memory.
The problem: a specification can't settle every call
Our test specification rejects "any ink, stamp, printed characters or marking on the shell, any size or colour." It also accepts "natural shell colour variation, longitudinal stripes and gloss." A faint white print sits between those two clauses.
A quality engineer settles a call like that in seconds. The knowledge then stays in their head or in a ticket, and the next inspection starts from zero. We wanted a correction to reach the next part, with a record of who made it and why.
How it works: a correction becomes a recalled rule
SpecLens is a one-page inspection app. You pick a part photo, and Muse Spark 1.3 from Meta checks it against your specification. You get Accept, Reject or Review, with a reason, a confidence score and a ring around any defect. If the decision needs fixing, you record the right decision and the visual rule behind it.
Four things then happen:
- Save. SQLite stores the correction and marks it pending.
- Retain. SpecLens sends it to Hindsight, then marks it synced.
- Recall. The next inspection calls
recallbefore it calls the vision model. - Cite. The model gets the recalled rule, and its decision names the correction ID.
A third Hindsight call, reflect, summarises the standards a workspace has learned. The Hindsight documentation describes all three operations.
The written specification stays fixed. Corrections reach later inspections through Hindsight.
We could have pasted every correction into the prompt. That works for five rules. Agent memory suits a list that keeps growing. Hindsight extracts facts from what we retain, and recall returns the ones that match our query. We cap each recall at 1,800 tokens and 12 facts, so the memory block has a fixed ceiling however many corrections a team saves.
The hard part: a recalled fact isn't always a rule
Retain: one call, safe to retry
data = self._post(scope, 'memories', {'async': False, 'items': [{ 'content': text, 'context': (f'Visual quality standards for ' f'{scope.part_family} at {scope.factory}'), 'document_id': correction['id'], 'update_mode': 'replace', 'metadata': { 'correction_id': correction['id'], 'inspection_id': correction['inspection_id'], 'scope_id': scope.id, 'reviewer': correction['reviewer'], }, 'tags': ['quality-standard', f'scope:{scope.id}'], }]}) The document_id and update_mode pair matters when a network call fails. A retry replaces the same document and does not create a second standard. The retained text also calls the rule "a clarification of the part specification, not permission to bypass other reject clauses", so a note about white ink can't weaken the rule on cracks.
Recall: Hindsight finds it, the audit record words it
Hindsight extracts facts from the text you retain, and our text holds both the mistake and the fix. In the B2 run, recall returned two facts. One was the standard. The other read:
The quality engineer Synthetic evaluation corrected the decision for a Whole hazelnut inspection to 'defect' with the class 'print'.
That sentence is true, and it is useless as an inspection rule. A fact that described the model's old error would be worse. So SpecLens never treats a recalled sentence as the rule itself. Hindsight decides what is relevant, and the audit record supplies the reviewer's exact words:
facts = self.memory.recall(scope) if use_memory else [] sources = {c['id']: c for c in self.store.corrections(scope.id) if c['sync_status'] == 'synced'} memories = [{**f, 'reviewer': sources[f['source_id']]['reviewer'], 'rule_text': sources[f['source_id']]['rule_text'], 'source_inspection_id': sources[f['source_id']]['inspection_id']} for f in facts if f['source_id'] in sources] SpecLens drops any recalled fact without a synced source in the current scope. This join also makes the citation real, because the ID in the model's answer points at a record a person can open.
Scope: one memory bank per specification
Two factories can disagree on what passes, and a revised specification can retire an old rule. Each Hindsight bank comes from the factory, the part family and the exact specification text:
identity = [self.factory.casefold(), self.part_family.casefold(), self.spec_text] if self.owner_id: identity.append(self.owner_id) data = json.dumps(identity, ensure_ascii=False) return hashlib.sha256(data.encode()).hexdigest()[:24] A new specification revision starts an empty bank. Good rules don't carry over on their own, so someone has to review them and add them again. We accepted that cost because silent carryover would make a later decision hard to explain.
Results: one rule changed one decision
We used one teaching photo and two held-aside source photos. Each held-aside source gave one faint-print image and one untouched control. Every image ran twice, with memory off and on, using the same pixels, model and specification. We retained one rule:
Inspect faint white characters closely. Sharp printed characters, including low-contrast white ink, are print defects. Broad smooth highlights and natural shell stripes alone are acceptable.
We wrote that rule ourselves for the evaluation. No factory engineer was involved.
| Check | Memory off | Memory on |
|---|---|---|
| Correct decisions | 3/4 | 4/4 |
| Marked parts caught | 1/2 | 2/2 |
| Untouched parts rejected | 0/2 | 0/2 |
One live pass on four synthetic cases.
The model had already rejected the teaching photo, so the rule came from a part it got right. It still changed the answer on B2.
The controls held too. A rule that says "inspect closely" could easily create false alarms. Both untouched parts stayed accepted with memory on, and one rationale said the model had "checked closely for faint/low-contrast white printed characters - none present".
What this does and does not show. This is four synthetic cases from two source photos in a single pass. It is not a benchmark, and a rerun could differ. Our first live comparison showed no difference at all, because both arms rejected the marked part. The raw responses are in the repo.
What we learned: four things the build taught us
- A true fact can still be a useless rule. Fact extraction is useful for retrieval. Your audit trail should still own the exact wording.
- Confidence is not correctness. The wrong accept scored 0.97 and the right reject scored 0.82. A confidence threshold would not have caught this miss.
- Memory goes last in the prompt. We first kept recalled standards in the system message. Moving them out raised cache reuse on a repeated photo from 369 to 1,265 of 1,325 tokens.
- Controls keep the test honest. A memory that only adds rejections will look great on a test set of defects.
Limits: what this does not show
- Synthetic inputs. The images are generated, the ink is a controlled overlay, and the model is stochastic.
- One part family. SpecLens covers four defect classes: hole, crack, cut and print.
- Light separation. Public visitors are separated only by a browser cookie.
- Near-duplicates. They still need manual exclusion from any evaluation.
- People decide. They stay responsible for the final disposition. The test that matters next is real parts with repeated runs.
Credits
Thanks to Code.in, an AI coding partner built in India, and to the Vectorize team for Hindsight. SpecLens was built by Aditya Arnav and Pallab Das as team Vulcan.
Code and evidence files: github.com/PDGamerSG/speclens. Live app: speclens.pallabdas.me. All sample photos are generated.



