Skip to content

Releases: mcp-tool-shop-org/facet

facet v0.8.0

Choose a tag to compare

@github-actions github-actions released this 20 Aug 02:39

A subject is built reference-first, and the brush takes its first stroke.

v0.7.0 made the canon a database and put a fail-closed gate in front of the spend. This
release is the first arc to use that from the beginning: A1 — "the archivist" — is the
first subject whose canon was ratified before a mesh existed
, and the first to reach a
committed brush stroke.

The order is the point

Every other subject on this route started from a form-exaggerated clay concept and acquired
its canon afterwards, which is how four arcs came to repair composition downstream of paint
that was wrong at the source. A1 inverts it. The reference carried its own embedded recipe;
the canon was walked and ratified at 16/16 surfaces, 10/10 profile hits, before any
geometry existed; and every stage since had something to be gated against.

What that bought, stage by stage: a mesh approved at the Director's eye, a venue that
reproduced the reference pixel-identically three times, an accepted eight-view twin ring
with a sha256 manifest, and two named contamination failures each measured to a mechanism
before anything was changed.

Across the whole arc the ControlNet strength was never touched. Every fix removed a
cause rather than applying force against one. That is the result worth carrying forward; the
asset is the demonstration.

Stroke one

The bake was approved 2026-08-19 — on identity and the garment set, and that is the whole
scope of that approval.
Then the brush opened.

invar   PASS   mean 0.014 lv, largest hot component 0 px outside the figure
               across 472,318 px tested
commit  PASS   3,585 texels written, holes 2,044,423 -> 2,040,838
               source atlas re-verified byte-identical afterwards

One generation, submitted once, completed once. Both gates run as separate calls with each
exit code read individually
— a shell chain once committed 47,020 texels past a fired ANDON
on this route, and that is why the sequence is written the way it is.

At the Director's zoom: the pale triangle at the vest collar-to-shoulder went plum and the
seam reads as one garment. It did not invent a face, turn the head, or paint a second vest.

The brush writes into holes only, and that decides what it can fix

texpass_iter commits edited pixels into hole texels only; styled texels are never
overwritten. Two consequences ship with this release, both stated on the front page rather
than discovered later.

A painted face comes out banded, and the brush structurally cannot fix it.
project_twins is winner-take-all — one camera wins each texel outright by facing weight,
ownership rather than averaging. A1's face is seen by the front view and the two 45° quarters,
and those twins disagree on skin value by R 13.0 / G 13.9 / B 18.3 across the accepted
ring, so wherever two UV charts on the face are owned by different cameras the disagreement
lands as a hard step. The bands are island boundaries, not dirt, and not the grey hole class.
Two remedies are named and neither is taken.

This was already present on the sheet the bake was approved from. An open defect on an
accepted artifact is not a contradiction — but the record must not read an approval as
covering a property nobody graded, so the scope of that approval is written down beside it.

Also in this release

  • scopes.strokes, ratified — eight stroke keys, each reusing the already-ratified
    scopes.views entry at the same yaw, because a stroke camera at a yaw is the twin camera
    at that yaw. Stroke order derived from a measured per-view brush canvas rather than
    inherited from another subject's.
  • The suite had been red for four commits and two folds reported it green. A flag landed
    in project_twins without moving its pinned registry table. Repaired, with the sweep's own
    output as the evidence that the classification is right rather than convenient: every
    profile returns to the exit code and undecided count it was already pinned at.
  • A new law: an ANDON that checks a source was NAMED is satisfied without the value ever
    ARRIVING.
    An emit gate refuses to guess a frame — but naming a profile silences it while
    supplying nothing, if that profile carries no block for that tool. The proxy fails
    precisely when the guard is needed. The law is recorded; the guard is deliberately not
    retuned.
  • A correction on this repo's own CHANGELOG. It stated "there is no manifest to bump."
    Four sites declare the version and the release gates on all four matching the tag. The
    false sentence is kept beside its correction rather than deleted, which is how every
    correction in this repo is handled.

Where it does not go

Strokes two through eight are blocked, on a decision nobody has taken: the brush's canon
gate evaluates at subject scope, and at view scope the prompt fails four of the eight
cameras. One stroke passing is not evidence about the others. That gets decided in the clear
or accepted permanently in writing — not in the afterglow of a pass.

facet v0.7.0

Choose a tag to compare

@github-actions github-actions released this 18 Aug 02:02

The gate closes fail-closed, a generation gets an identity, and a surface starts becoming a set of faces.

v0.6.0 made the canon data and put a gate in front of the spend. This release closes the
three holes that were still in it — the gate was optional, a generation could not be
replayed, and a canon surface was still only a word.

Fail-closed at every authoring site

The v0.6.0 gate read if args.canon:. Omit the flag and it did not run, and nothing said
so — and texpass_loop.ps1, the shipped driver, called texpass_brush without a profile.
A gate a missing flag can separate from the action it gates is not a gate.

Now a tool that authors a spend and is given no canon refuses:

$ python tools/restylize_views.py --emit-only --inputs IN --outdir OUT --prompt "..."
canon_gate.Andon: ANDON: no canon: pass --canon PATH, or --subject NAME,
                  or --no-canon --subject NAME for an identity-only subject

--outdir is never created. The escape for a subject that genuinely has no canon is
census-backed and cannot be worn by a subject that does:

--no-canon --subject GALLEON   ->  proceeds, prints  [canon] UNGATED: GALLEON identity exists, surfaces missing
--no-canon --subject W3        ->  REFUSED: W3 has surfaces at canon/w3.surfaces.json

Wearing the escape means a deliberate edit of the census, and you cannot invent a subject
that has no IDENTITY. That is what stops it becoming a checkbox. Wired at
restylize_views, texpass_brush, brush_cloud_step — which writes the JSON that gets
submitted to the cloud — and e12_pair_cloud_step, which authors the paid twin graph. Two
sites were refused with reasons rather than wired: ig2mv_licensefree is a different
backbone with no subject, and e37_fire_repaints replays a recorded prompt, where a
refusal would halt a faithful replay.

The gate now reads both directions

Checking that a prompt contains the canon finds a thin prompt. Checking that everything
in the prompt is canon finds a phrase naming something the subject does not have — and
there was one in the live default: gold necklace, which this repo had already measured as
misnaming the gold belt medallion, "and the element survives by accident."

A covering prompt with that phrase appended now returns missing: 0 and refuses anyway,
naming the clause. Schema 2 declares the legal non-surface clauses so the reverse check does
not fire on plain grey background; schema 1 files stay one-directional, so an older
subject cannot start refusing its own style words.

A generation record with an identity

gen_record extends the existing sidecar rather than replacing it — every recorded
*_gen.json still reads. It adds an immutable recipe_id (content hash after NFC and
CRLF→LF normalisation), a movable alias excluded from that hash, the declared producer,
and the canon the gate allowed.

The fields we cannot reach are recorded absent with a reason rather than omitted or
faked: checkpoint_hash, lora_weight_hash, driver, hardware and library are not returned
by the cloud transport, and validation refuses a string in those slots. A field that
reads as filled when nobody can know it is worse than a hole. The LoRA is half-reachable and
says so — the declared card name is in the graph we write, the weight tensor is not, and
hashing a filename and calling it provenance is a known bug in another tool's history.

A worksheet, and the first face binding

canon_worksheet emits every surface a subject's kind implies, so a hole is a row before
anyone has named it, and is structurally incapable of filling an occupant — tested with
a poison phrase that arrives with a surface already assigned and is not written.

canon_bind gives a surface a face set. Today it is honest rather than impressive: 27
rows, every one empty, 0.00% of the figure bound.
Two rows reach proposalblade and
grip, the only names in the hand-box file that resolve as surface ids — each carrying its
boxes as seeds with their original "PROPOSAL. Not a ruling" provenance. skirt stays
unmatched rather than being silently mapped to kilt.

The unit is the face: faces survive a re-bake, texels do not, and this route re-bakes.

Measured, and closed as negative

  • The target-view compositor does not fix the flat class. It already existed and was
    already the default; against the flat classifier it raises the count at the named target
    (38 → 40) and sharply at two others (23 → 64, 36 → 110). Shape is ownership, colour is
    not — an ownership policy cannot repair a cross-view colour disagreement on a
    correctly-attributed surface.
  • Co-location survives from-scratch specification. The gold forearm plate is absent from
    the sixteen-element from-scratch arm, and the compound form had already been tried and
    split.
  • Element count cannot be separated from element identity on the plates already paid
    for, and the reason is structural rather than statistical. What they do give is a
    one-sided bound: over an element ladder of 10 → 17, count removed nothing that was
    present at 10.

Corrected in place

  • The front page told readers a target-view compositor was "the scoped repair and costs
    nothing."
    Measured, it goes the wrong way. Corrected with the measurement beside it.
  • The asset accepted at Gate 1 and the asset later called far from perfect are the same
    file.
    Nothing said so until a seat assembling a labelled accept/reject set found its two
    classes collapsing onto one tree and halted. Acceptance is a ruling on an artifact at a
    date, not a permanent grade — and any comparison treating "accepted" as a label needs a
    per-surface class. Noted on both handbook copies.
  • A DIRECTOR-VERIFIED label on a set of region boxes is unsupported at source. It sits
    in a read-only tree and stays a record item rather than an edit.

Known

The canon binds 0.00% of the figure — scopes.views is empty by construction, and the
hand-box file reaches 7.95% strictly. Until a surface is a set of faces, is this region the
wrong material
is not computable, and no automated check for that class exists: the nearest
detector fires at 39.90% on a pauldron that is correctly gold, above five of the seven
regions the Director named. Filling the face sets and the scope lists is a human walk, and
the worksheet only makes it cheap.

Suite 1338 tests, 1284 hermetic. Fifty-six experiments in the record, verified on four
legs with byte-identical determinism.

facet v0.6.0

Choose a tag to compare

@github-actions github-actions released this 17 Aug 10:21

The canon becomes data, and the gate stands in front of the money.

canon/W3-IDENTITY.md specified seventeen elements. The prompt that generated the twins
named sixteen. The profile default that a fresh run would actually use named six. Nothing
connected any of them, so four arcs spent themselves repairing composition downstream of
paint that was wrong at the source.

This release makes that impossible to repeat. The canon is a machine-readable database
keyed on surface, and canon_gate sits inside restylize_views and
texpass_brush, before the output directory is created. A generation whose prompt does
not cover the ratified canon is refused, and nothing is written.

canon_gate 1.0.0  census  (occupancy is not ratification)
subject      named   occupancy   ratified   prof_hit surfaces
W3              19       24/24      24/24       5/19 canon/w3.surfaces.json
GALLEON         13           -          -      11/13 NONE
DRAGON          11           -          -      10/11 NONE
LONGSWORD        5         5/5        5/5        4/5 canon/longsword.surfaces.json
E10-LAYER        1           -          -          - NONE
LOGO             0           -          -          - NONE

prof_hit 5/19 is the specimen, left deliberately broken: the live default is the string
that would be used, and the first run with --profile character.json is supposed to
halt. Repairing it would delete the evidence.

Surface, not element — and it is why the holes were findable

An element list cannot show you what is missing. The leather-wrapped grip was absent from
a seventeen-row list and no reading of that list ever revealed it; a human looking at a
picture did. A surface list with a nullable occupant makes the hole a row, and W3's
holes turned out to be both hands and both greaves.

Joints are first-class rows between two surfaces, because the missing specification at
every failed region was the cut and never a fifth garment. Sleeveless is a bare
occupant plus a forbidden word, not prose. Verification writes a sidecar, so the canon
file can never certify itself.

Added

  • tools/canon_gate.py — coverage, occupancy, the author-time prompt check, the
    cross-subject census, and a sidecar verifier (t87, t91).
  • tools/evidence.py — the diagnostic layer. Seven arcs had each written their own
    sheet builder and three seats wrote a surfid decode in one session; one importable
    surface now emits the provenance classification, the acceptance sheet and the numbers
    with their denominators declared (t90).
  • tools/flat_trace.py — render pixel to atlas texel to contributing view to that
    view's twin (t89).
  • tools/region_disagreement.py, tools/boundary_repair.py,
    tools/unmapped_readout.py (t85, t86, t88).

Suite 1182 → 1266, 1212 hermetic.

What was measured and did NOT work

Reported because a negative result closed a route rather than leaving it as an untried
option:

  • The flat coloured patches are not a fill artifact. Orphan fill measures below its
    own base rate at them, and the same defect is present in a render built from an atlas
    that predates the repair blamed for it.
  • There is no geometry to snap a material boundary to. One PBR material on the whole
    mesh, 13,715 atlas islands against sixteen named materials, and a palette that cannot
    separate gold from leather because both are warm. 354 texels of 2.4 million.
  • The magenta is cosmetic. 0.22% of the figure; a 46x atlas-side reduction moved the
    on-screen count by six pixels.
  • The flats trace to a plate nobody had checked. The render view's twin is clean; a
    different view owns 97 of 115 defect pixels and its paint is that colour. The patch is a
    scatter artifact and the colour is a real cross-view disagreement on an already-named
    surface — so regenerating twins is not justified by "the defect is in the twins".

Corrections in place

  • Two of three Blender citations in the repo's own law book were wrong, resolved one call
    each at /api/v1/: #162226 is open, not merged, and #119393 is a single defect,
    not a catalogue
    . The correction is load-bearing — the merged fix cannot reach a UV that
    lands in a packer gutter.
  • The claim that the generation prompt named six elements welded two files into one false
    sentence. The workflow that made the twins named sixteen; the six is the profile
    default.

Known, and stated rather than implied

The gate checks that the subject prompt contains the ratified canon phrases. It does not
check paraphrases, per-view stems, unratified drafts, subjects with no surfaces file, or
whether a named material landed on the right surface.
Four subjects have an IDENTITY.md
and no surfaces JSON; generating those files without walking the reference would ship
unwalked lists as if they had been walked, so they are left undone on purpose.

Full detail, with the ruling behind each claim: CHANGELOG.md.

Compensators

action irreversible? compensator owner
npm publish yes npm deprecate @mcptoolshop/facet@0.6.0 and publish a fixed patch; the version stays visible, marked the publishing session
PyPI upload yes yank the release — it stays resolvable for pins but is not selected for new installs — then publish a fixed patch the publishing session
gh release create + tag yes, in practice gh release delete v0.6.0 and delete the tag; anyone who already fetched a binary keeps it, so treat as one-way the publishing session
the version bump commit no git revert — five declarations move together and T27 refuses a mismatch any session
the wheel/binary build no artifacts are derived; rebuild from the tag any session

The three irreversible rows are the Director's act.

facet v0.5.0

Choose a tag to compare

@github-actions github-actions released this 17 Aug 06:26

The plates compose, and the projector question closes.

The shipped atlas route was destroying paint that the eight per-view plates agree on.
Rebuilt from the per-view bundle under border × facing × visibility weights, the renders
cleared the Director's acceptance bar for the first time on this route — twice, across
two arcs, with one defect class left open and named.

One session ran five arcs (E45–E49), two dispatched executor seats and three runner
seats, and six build rounds through an outside review channel whose nominated
calibration claims held ten for ten — every one verified here by running it before
anything trusted it. Zero cloud credits were spent.

Added

The S3 chain, seven tools.

tool what it does
emit_view_aovs.py per-view G-buffers of the shipped state, anchored by pixel-exact reproduction of the recorded silhouettes — 16/16 cameras at 0 px
s3_composite.py the existence-proof compositor: view-dependent and view-independent stills, disagreement diagnostics, a flow hook
flow_estimate.py dense Lucas–Kanade with sparse per-component confidence, and the aperture problem handled rather than hallucinated
s3_run.py the bundle runner, flow A/B built in
s3_sheet.py + regions native-pixel acceptance sheets carrying provenance as a panel
atlas_from_aovs.py texel-driven atlas rebuild, owner/blend × flow off/on
twin_mesh_warp.py the per-tile correspondence instrument, validated on constructed truth before any real measurement

Tests t77–t84; the suite grew 1098 → 1182 (1135 hermetic), with the thirteen T34
count surfaces moved in the same commits.

The warp is measured. Interior tile offsets exceed silhouette offsets on 8 of 8
views
— medians 3.46–11.12 px against 1.16–3.00 — and wrong-pairing controls separate
12.5×, so the instrument discriminates. The twin ring turned out to be eight flat
cameras
; the elevated pair are brush cameras and no twin exists at elevation, which
retired a premise the record had carried.

Flow-corrected compositing reduces cross-view disagreement on 18 of 18 measured rows
directionally uniform, but magnitude only a trim (1.4–3.2 px median at 16–27% coverage).
The lever was the projection policy itself, not the correspondence.

Changed

  • callieri_border.py 1.0.0 → 1.0.1 — the inf−inf RuntimeWarnings silenced by masked
    subtraction, proven byte-identical across all four public surfaces on an inf-background
    fixture and a real frame, with the warning provocation demonstrated against the old
    form and the T76 calibration pin untouched.
  • docs/index/conventions.json paid_for_by marched E4[0-4] → E50 as arcs landed.
    Its andon fired three times in one day — each firing a designed leg doing its job — and
    earned a standing order now in the record: the arc bound and the instrument census
    re-run are the last corpus-touching steps of every fold.

Fixed in this release

v0.5.0 was tagged once and published nothing. The tag went onto a tree that still
declared 0.4.0 in every site the release gate compares, so the gate refused and no
Release was cut — while the session handoff recorded the publish as successful. The gate
exits at its first check, so its annotation named one file when four declarations plus
the server version were stale.

Also repaired: the hermetic CI job checked out at depth 1, while t84's diff leg reads a
historical blob with git cat-file. It passed on the development rig, where the full
history is present, and failed on the runner — a check hermetic with respect to training
assets and not with respect to clone depth. Now fetch-depth: 0, with the two
coverage-removing alternatives named and rejected in the workflow file itself.

Known, named, and staged

  • The fill-pass polygon class — flat-coloured angular patches on the accepted-grade
    sheets, the one open ruling against them. Hypothesis tagged in provenance masks; a
    repair arc is running.
  • Never-seen surface — 4.65–5.57% of valid texels fail the depth gate in every
    flat-ring view. That is a policy decision, not a bug.
  • The canon build-out, identified as the crux: the recorded generation prompt names
    six elements, and several surfaces the defects sit on are named zero times.

Full detail, with the ruling behind each claim: CHANGELOG.md.

Compensators

action irreversible? compensator owner
npm publish yes npm deprecate @mcptoolshop/facet@0.5.0 and publish a fixed patch; the version stays visible, marked the publishing session
PyPI upload yes yank the release — it stays resolvable for pins but is not selected for new installs — then publish a fixed patch the publishing session
gh release create + tag yes, in practice gh release delete v0.5.0 and delete the tag; anyone who already fetched a binary keeps it, so treat as one-way the publishing session
the version bump commit no git revert — five declarations move together and T27 refuses a mismatch any session
the wheel/binary build no artifacts are derived; rebuild from the tag any session

The three irreversible rows are the Director's act. The tag move that fired this
release was his.

facet v0.4.0

Choose a tag to compare

@github-actions github-actions released this 10 Aug 01:56

The measurement server ships.

Four releases put a record index in the wheel and left the eight measurement tools
behind. pip install facet-mcp gave you facet-index and facet-mcp — and nothing
that measures a mesh, because the wheel held two .py files while the served tools
invoke their instruments as subprocesses. There was nothing to invoke.

It was invisible because this repo is the checkout: the tool worked where it was
built and had never been anywhere else.

pip install facet-mcp[measure]
mesh_stats  <a control mesh>   ->  faces 786432, components 1, watertight true
                                   + an identity envelope carrying the instrument's
                                     own sha256

Measured from a clean venv with no checkout on the machine, by running a verb — never
--help, which is how four green pipelines missed the last one.

Two extras, and what you get depends on your Python

[measure] is the tier that resolves on every Python this package claims — four
tools, no heavy native dependency. [measure-full] adds the four geometry tools, which
need open3d.

your Python [measure-full] gives you
3.11 / 3.12 all eightopen3d installs from PyPI
3.13 four; mesh_stats · mesh_topology · measure_report · anchor_check

open3d 0.19.0 is the latest release and publishes cp38–cp312 wheels with no sdist.
The requirement therefore carries python_version < "3.13", so on 3.13 the install
succeeds without it and reach_ceiling, thin_extent_curve, offsurface_rate and
texel_provenance exit 4 REFUSED naming what they need — instead of the whole
install failing on a resolver error.

All eight on 3.13 is one documented command, because Open3D ships current cp313 wheels
on its rolling devel channel and a direct URL is legal on a command line even though it
cannot appear in published metadata:

pip install https://github.com/isl-org/Open3D/releases/download/main-devel/open3d-0.19.0-cp313-cp313-manylinux_2_35_x86_64.whl

⚠ Linux's filename is stable; Windows and macOS devel wheels are +<sha>-suffixed and
move as main moves. That devel build is what this route's own open3d-dependent numbers
were measured against
— a real comparability boundary, since the identity envelope
records the instrument's hash and not its dependency set.

The defect underneath, which was this project's own, twice

measure_mcp carried REPO = dirname(__file__)'s parent — in a wheel, <venv>/Lib.
That is v0.3.1's defect verbatim, in a file written after v0.3.1 fixed it
elsewhere. The consumer sweep that found the others could not have caught it, because
the consumer did not exist yet.

The repair is a distinction the first fix never drew:

  • REPO answers where is the corpus — the two-marker property test, returning
    None rather than guessing.
  • tool_path answers where is the instrument — resolved beside the module.
    One expression correct in a checkout and an install, because the record markers key on
    a corpus that cannot ship, while instruments are code that does.

The identity envelope now builds its path the same way, because two path expressions for
one file is how a payload comes to certify an instrument that did not run.

Also in this release

  • The measurement server is reachable over MCP at all. It was declared in no config,
    so no session could reach it. Registered with a test — a subprocess over stdio that
    asserts the payload's instrument sha256 equals the file on disk.
  • A missing dependency is a refusal, not a runtime error (exit 4), which is what
    makes a four-of-eight install usable rather than mysterious.
  • The polish arc's eight per-profile anchors land as permanent tests — and one
    halted: a route tool had changed under an already-accepted asset, caught on the
    gate's first outing.
  • A reconstruction noise floor, which this record did not have. Three runs of one
    input at one seed are bit-identical through remeshing and diverge in decimation:
    faces ±0.27%, shells ±1, non-manifold edges ±18.
  • The hollow-shell finding's reach is narrowed. Its evidence base is prop, beast and
    vehicle — no character — so on the character class the wall structure is ruled
    unmeasured, which is not a claim of solidity. Every consumer-facing clause is
    unchanged: a volumetric predicate still meets a shell.

Full detail, with the ruling behind each claim: CHANGELOG.md.

Compensators

action irreversible? compensator owner
npm publish yes npm deprecate @mcptoolshop/facet@0.4.0 and publish a fixed patch; the version stays visible, marked the publishing session
PyPI upload yes yank the release (it stays resolvable for pins, but is not selected for new installs); publish a fixed patch the publishing session
gh release create + tag yes, in practice gh release delete v0.4.0 and delete the tag; anyone who already fetched the binary keeps it, so treat as one-way the publishing session
the version bump commit no git revert — five declarations move together and T27 refuses a mismatch any session
the wheel/binary build no artifacts are derived; rebuild from the tag any session

The three irreversible rows are the Director's act. Nothing in the preparation for
this release fired one.

facet v0.3.1

Choose a tag to compare

@github-actions github-actions released this 09 Aug 06:50

The install that could not find the record.

Every released version through v0.3.0 shipped a wheel whose two commands could not
locate the corpus they exist to serve. v0.3.0's own release notes named the defect at
publication — this is the arc that fixes it.

facet-index build          FAILED   resolved the record against <venv>/Lib
facet-index q <term>       FAILED   without an explicit --db
facet-index claims         FAILED   (v0.3.0's notes said this one worked; it did not)

The root is now resolved by TESTING FOR THE RECORD rather than by assuming a
location. From inside a checkout both commands find it. From anywhere else they exit
4 REFUSED, naming both directories they tried and both markers they looked for —
a refusal instead of a wrong answer, which is the same rule the index MCP already
served under. Measured on a wheel built from main and installed into a clean venv.

$FACET_INDEX_DB is read by both commands now, and it selects which index,
never which corpus.

Why four green releases shipped it

Every check exercised --help. release.yml's wheel step said verify the wheel runs
from a clean venv
and ran the one surface that needs no record — so the one thing the
package exists to do was the one thing nothing tried. That step now runs a verb, and
CI runs the artifacts tier it had been silently skipping.

Changed

  • The deletable-gate class closes. The last 133 ANDON sites across 43 files
    — the measurement instruments — now raise instead of assert, after v0.3.0's 88 and
    57. 278 converted in total. Exactly one bare ANDON assert remains anywhere
    under tools/: superseded/texpass_thin_mask.py, permanently out of scope because
    those tools are kept so anyone can run them and watch them fail the same way. It is
    pinned by name so a future sweep cannot tidy it away.

    None of the 133 is in this package — the wheel ships facet_index and
    record_mcp only. This is an internal change, and the patch bump is not concealing a
    published behaviour change.

  • 28 ANDONs that already raise SystemExit across 12 files are unchanged and
    pinned. SystemExit survives -O, so none of them carried the defect.

Added

  • The front door's counts are under a test. It fails CI on any watched surface
    stating a stale count, and it caught a real drift on its first run that no
    coordination rule had seen. The matcher is phrase-shaped rather than proximity-shaped
    — a ±90-character window returned 45 hits of which six were not test counts at all.

No suite total is quoted in these notes. It is a live-moving number and a published
release note is a region the front-door count test deliberately does not sweep — so a
total written here is the one kind of count nothing catches when it goes stale.

Install

npx @mcptoolshop/facet          # zero-prerequisite, SHA256-verified binary
pip install facet-mcp==0.3.1    # fixed in this version; run it from inside a checkout

Unchanged from v0.3.x: four accepted assets across four subject classes at zero credits,
a four-leg-verified SQLite+FTS5 index over the whole evidence trail, and open defects
named on the front page rather than in a footnote.


Compensators: gh release delete v0.3.1 --yes · git push --delete origin v0.3.1 ·
git tag -d v0.3.1 · npm unpublish @mcptoolshop/facet@0.3.1 (72h) or npm deprecate
after · PyPI cannot re-upload a version — yank from project settings.

facet v0.3.0

Choose a tag to compare

@github-actions github-actions released this 09 Aug 02:22

The gates stop being deletable.

assert is a statement the interpreter is licensed to remove. python -O and
PYTHONOPTIMIZE=1 delete it silently — and this repo had been using it for the checks
that decide whether an irreversible step proceeds. Measured on one gate before the
repair, on the pinned interpreter:

python                      GATE FIRED
python -O                   GATE SILENT, execution continued past it
PYTHONOPTIMIZE=1            GATE SILENT, execution continued past it

The gate never spoke, the write proceeded, and the process exited 0. That is worse
than the shell chain the original rule was written for — a chain at least lets the halt
print before walking past it.

145 gates now raise. E22
converted 88 across the write-head, the index and the published server;
E23
converted 57 more across the twelve route tools that produced four accepted assets. Every
one is a pure move — no message reworded, no condition tightened — and that is proved
by whole-file AST equality against the prior commit rather than by anyone reading a diff.
No conversion was reverted.

Changed

  • A new exit code: 4 = REFUSED. A fired gate and a failing verify leg both leave
    with it — the tool ran correctly and is telling you not to proceed, which is neither
    a user error (1) nor a runtime error (2). 0/1/2 are unchanged, 3 stays
    reserved and unused. The certificate field and the test fixture now read the tool's own
    constant instead of a hardcoded integer, so they cannot drift apart from it.

Added

  • Tests that the old construction made impossible. Each converted gate is asserted to
    refuse under a normal interpreter and under -O and under PYTHONOPTIMIZE=1,
    with the write-path gates additionally leaving no artifact when they fire. The suite
    went 248 → 370. No test asserts that PYTHONOPTIMIZE=1 disables a gate — that
    would anchor the defect rather than close it.

Known, and named rather than omitted

134 ANDON checks are still bare asserts — 132 in tools/diagnostics/, one in
tools/verify/, and one in tools/superseded/ that will stay that way on purpose,
because those tools are kept so anyone can run them and watch them fail the same way.
None is in a command this package installs. That count is pinned by a test, so the next
arc's scope cannot drift silently.

One gate was found that cannot fire at all — shadowed by an earlier check on the only
path that reaches it. It is kept and annotated rather than deleted, because it is a
precondition on a function's contract and not on today's single call site.

Install

npx @mcptoolshop/facet          # zero-prerequisite, SHA256-verified binary

Corrected after publication, at the release read-back. This section also offered
pipx install facet-mcp==0.3.0. That path cannot find the record. The wheel installs
facet_index as a top-level module, so it resolves the corpus and the default index
against <venv>/Lib — which holds neither: build fails, q fails without an explicit
--db, and the server's corpus-reading tools refuse. $FACET_INDEX_DB is read by
facet-mcp and not by facet-index.

This is not a v0.3.0 regression — the 0.2.0 wheel fails identically, and it has been
true since the extraction. v0.1.1 fixed the frozen branch and left the wheel branch
behind. The npx binary above is unaffected and is the supported path. Both defects
are measured and located in code in
known-defects.md;
the fix is a behaviour change to two published commands and gets its own arc rather than
a hotfix.

Found by running a verb on the installed artifact instead of --help — which is also
why release.yml's own "verify the wheel runs from a clean venv" step went green: it
runs --help and --print-tools, and neither touches the corpus or the database.

Unchanged from v0.2.x: four accepted assets across four subject classes at zero credits,
a four-leg-verified SQLite+FTS5 index over the whole evidence trail, and the open defects
still named on the front page rather than in a footnote.


Compensators: gh release delete v0.3.0 --yes · git push --delete origin v0.3.0 ·
git tag -d v0.3.0 · npm unpublish @mcptoolshop/facet@0.3.0 (72h) or npm deprecate
after · PyPI cannot re-upload a version — yank from project settings.

facet v0.2.0

Choose a tag to compare

@github-actions github-actions released this 08 Aug 20:35

The operator contract of the two installed commands. A behaviour change to a
published CLI, so it takes a minor bump. Scope is what facet actually installs —
facet-index and facet-mcp — and no other tool in tools/ is touched. Full
evidence: E21.

Changed

  • Exit codes now mean what the ship gate says they mean. Measured before the
    change, through a subprocess, on twenty rows across both commands: a user error
    exited 2 (argparse's convention) and a runtime error exited 1 (CPython's
    default for an uncaught traceback). The surface was inverted at both ends, not
    one
    — the gate line had named only the argparse half, and the second inversion was
    found by running the matrix rather than by reading the code. Now: 0 ok, 1 user
    error, 2 runtime error.
  • 3 is declared and deliberately unused. No verb of either command has a
    partial-completion path. verify reporting three passing legs and one failing one
    has completed, and reports a measured outcome. A code is not populated by
    inventing a path for it to describe.

Added

  • No raw traceback reaches you without --debug. An unexpected exception now
    leaves as a structured failure naming its cause and the next step. --debug
    restores the traceback and changes nothing else — same exit code with and without,
    and the artifact a build writes is byte-identical across the pair.
  • --debug is confined by test, not by intention. A gate carries no skip flag, so
    the new flag is checked against that rule: an AST walk pins that the identifier is
    read only in the two functions deciding what gets printed after a failure has
    already been decided, and a fired gate still refuses with --debug set. The closed
    flag allowlist — the guard that exists to make a new flag expensive — widened by
    exactly one, in writing, with the condition attached.
  • 30 new tests, every code asserted through a subprocess (a console script's exit
    status is a property of a process; main() returning 2 is a different claim), and
    every code paired with a can-fail leg that must produce a different number.

Unchanged, on purpose

Two outcome classes keep the codes they had, because what they deserve is a ruling and
not an executor's pick: a failing verify leg — its return value is also the
verify_exit_code field of the schema-versioned certificate that record_health
serves, so moving it moves a persisted artifact and not just a shell's $? — and a
fired ANDON
. Both are reported with their options and consequences rather than
guessed at. claims stays 0 whatever it finds, which was already ruled.

Not done, and named rather than quietly dropped

Logging levels are not shipped. The silent/normal/verbose boundary was reserved for
a ruling before it ships, and the census that ruling needs is now measured: of
verify's 35 print sites, zero are progress chatter — they are separators, leg
headers, measurements and verdicts — and facet-mcp parses verify's stdout to build
its certificate, so a quiet verify would break it. That is not a philosophical
objection to suppressing output; it is a live dependency.

Install

npx @mcptoolshop/facet          # zero-prerequisite, SHA256-verified binary
pipx install facet-mcp==0.2.0   # or the Python package directly

Unchanged from v0.1.x: four accepted assets across four subject classes at zero
credits, a four-leg-verified SQLite+FTS5 index over the whole evidence trail, and the
open defects still named on the front page rather than in a footnote.

Known, and open

The repo's ANDON gates are bare assert statements, which python -O and
PYTHONOPTIMIZE=1 delete silently — measured, dispatched as E22, and not fixed in
this release
. It does not affect the two installed commands' exit contract above; it
affects the measurement tools in tools/. Nothing is claimed corrupted. It is named
here because a release that knows about a defect and does not say so is the thing this
repo exists to avoid.


Compensators: gh release delete v0.2.0 --yes · git push --delete origin v0.2.0 ·
git tag -d v0.2.0 · npm unpublish @mcptoolshop/facet@0.2.0 (72h) or npm deprecate
after · PyPI cannot re-upload a version — yank from project settings.

facet v0.1.1

Choose a tag to compare

@github-actions github-actions released this 08 Aug 18:43

A patch for a defect that only existed in the artifact you actually download.

v0.1.0's binary was wrong about your machine. Inside a PyInstaller onefile,
__file__ lives in a temp extraction directory — so the server resolved its default
index against that, printing db: C:\Users\…\Temp\docs/index/facet.db (a path that
cannot exist), and every refusal hint told you to run
python tools/facet_index.py build — a command with no tools/ directory to run it
in, and possibly no Python at all.

Fixed

  • The default index resolves against the working directory when frozen. That is
    the honest default: you run facet from inside the checkout whose record you want
    served. An explicit --db or $FACET_INDEX_DB still wins, as before.
  • The refusal hint follows the runtimefacet-index build --db <path> in a
    binary, the source command in a checkout. Every refusal here names the next step,
    and the next step has to be one you can actually take.

How it was found

Not by CI, which was green. Not by the wheel test, which passed. Not by the console
scripts, which ran. Every one of those exercises the source checkout, where the
repo root is the repo and the advice is correct.

It was found by installing the published package and reading what it printed. A
green pipeline verifies the thing it built, not the thing a user receives.
The new
tests exercise the frozen branch directly rather than trusting that a source-tree run
implies a binary run.

Install

npx @mcptoolshop/facet          # zero-prerequisite, SHA256-verified binary
pipx install facet-mcp==0.1.1   # or the Python package directly

Unchanged from v0.1.0: four accepted assets across four subject classes at zero
credits, a four-leg-verified SQLite+FTS5 index over the whole evidence trail, and the
open defects still named on the front page rather than in a footnote.


Compensators: gh release delete v0.1.1 --yes · git push --delete origin v0.1.1 ·
git tag -d v0.1.1 · npm unpublish @mcptoolshop/facet@0.1.1 (72h) or npm deprecate
after · PyPI cannot re-upload a version — yank from project settings.

facet v0.1.0

Choose a tag to compare

@github-actions github-actions released this 08 Aug 18:17

Four accepted assets, four subject classes, zero credits.

facet turns a styled 2D concept into a textured 3D asset, with the style applied on
the asset
in texture space rather than painted per view and stitched. Feed it a
form-exaggerated clay concept and it returns a textured mesh whose colour came from a
styled reference of that mesh, with everything the reference could not see filled by
a masked inpainting brush and a surface-aware dilation.

Every stage runs on local hardware, and no non-commercial licence appears anywhere in
the chain.

Install

The record index ships as an MCP server, so an assistant can query the evidence trail
instead of reading it:

npx @mcptoolshop/facet            # zero-prerequisite; bootstraps a managed venv
pipx install facet-mcp==0.1.0     # or install the Python package directly

Two commands come with it — facet-mcp (the stdio MCP server, six tools) and
facet-index (build / verify / q / claims).

The four assets

Each was accepted by the Director at his own zoom — on the finished GLB, or on
full-size sheets — never by a metric clearing a threshold.

subject class accepted reference / brush / dilation
Character (W3) humanoid 2026-08-04 68.8 / 4.2 / 27.0
Galleon vehicle, thin rigging 2026-08-05 36.89 / 6.87 / 56.24
Dragon beast, wing membranes 2026-08-07 44.15 / 3.07 / 52.78
Longsword prop, near-2D, grey-on-grey 2026-08-08 45.25 / 2.07 / 52.68

Shares are of valid texels and are not comparable across subjects — a ship hides
most of itself from eye level and an animal hides half. Read each against its own
pre-registered reach ceiling, against which they land 86–93%.

It is a pipeline, not a one-character generator

Contradict the specification on eight named elements and the prompt wins 8 of 8
median ΔE 46.3 against 6.2 on five held controls — while the figure stays the same man.
Structure is held by the mesh and the control; named attributes ride the prompt.

The record is the product as much as the pipeline is

  • 213 tests at two seats' hands, 205 of them hermetic and reproduced by paths-gated
    CI on every push.
  • A four-leg-verified SQLite + FTS5 index over the whole evidence trail: byte-identical
    determinism across interpreters, counts checked against independently written greps,
    zero dangling pointers, and a seeded question set that grows with the record. It found
    a ruling count the prose had wrong at three sites, by counting the record itself.
  • Twenty experiments, each with its predictions written down before the measurement,
    and its ruling written by a session that did not run it.

What this release does NOT assert

This is 0.1.0 deliberately. The texture stage is not finished, and the open defects are
on the front page rather than in a footnote: the blade band takes 0.00% of stage-1
reference on all eight cameras, stroke seams are not levelled, dilation bleeds between
unrelated atlas islands, and every reconstruction on this route is a hollow double-walled
shell. Three testability seams are dispatched and untaken, and the repo's own
highest-value open question — fit_background at frame-edge figures — has never been
looked at.

A 1.0.0 would assert a stability this route has not earned. Four accepted assets earn a
first release.


Compensators: gh release delete v0.1.0 --yes · git push --delete origin v0.1.0 ·
git tag -d v0.1.0 · npm unpublish @mcptoolshop/facet@0.1.0 (72h) or npm deprecate
after · PyPI releases cannot be re-uploaded at the same version — yank with
pypi.org project settings.