Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ jobs:
steps:
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with: {node-version: "22", registry-url: "https://registry.npmjs.org"}
# npm's OIDC trusted publishing needs npm 11.5.1 or newer; Node 22 still bundles
# npm 10, which performs no OIDC exchange at all. The publish then goes out
# unauthenticated and the registry answers `404 Not Found - PUT`, which reads
# exactly like a missing package rather than a missing credential -- the failure
# that sent 1.0.0 out by hand, permanently without provenance.
- run: npm install -g npm@^11.5.1
- run: npm --version
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: tarball
Expand Down
10 changes: 5 additions & 5 deletions fallback.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ const UNSUPPORTED={
request:[],
configuration:[],
// `hull_vertices`, `compression_ratio` and `max_compression_pressure_kpa` left this list
// in , the last engine to gain both the solver behaviour and the independent
// in, the last engine to gain both the solver behaviour and the independent
// validation the staged rollout requires.
item:[],
// `pallet_overhang_limit` was reserved in the schema by at the 1.1.0 contract
// freeze and is refused everywhere until an engine implements it from a request: a field
// a caller can set and the solver ignores is worse than a refusal.
// `access_directions` left this list in , which wired the reserved field through
// `access_directions` left this list in, which wired the reserved field through
// to the stop-accessibility rule in all four engines at once.
container:['pallet_overhang_limit'],
obstacle:[],
Expand All @@ -37,7 +37,7 @@ const UNSUPPORTED={
// caller that spells the default out must be served, not refused. What is unimplemented
// is a *value*, and the refusal names it -- packing a `convex_hull` item as its bounding
// box would return a plan that looks valid and does not physically fit.
// Empty since : this engine implements every value the schema defines. The guard
// Empty since: this engine implements every value the schema defines. The guard
// stays because the next reserved value will need it.
shapeType:[],
};
Expand Down Expand Up @@ -1603,7 +1603,7 @@ if(solverAlias===null&&requestedSolvers.length){
winner.termination=aggregateTermination(starts);
winner.algorithm=withPortfolioEffort(winner,runs);
const alternativeLimit=Math.max(0,(req.configuration?.alternatives??3)-1);
// The sentinel is a search device, never an answer -- alternatives included ( review).
// The sentinel is a search device, never an answer -- alternatives included (review).
winner.alternatives=runs.filter((run,index)=>index!==winnerIndex&&!run.unpriceableDetail).sort((a,b)=>compareScore(a.score,b.score)).slice(0,alternativeLimit);
return finalizeOutermost(winner);
}
Expand Down Expand Up @@ -2275,7 +2275,7 @@ for(const c of packed){scoreCost+=c.tmpl.cost_minor??0;
// to invent -- so the refusal fires, but once, at the outermost frame, on the packing
// actually selected for return: a portfolio sibling with a priceable answer must not be
// aborted by this run's refusal. Rust, Python and PHP refuse at the same single choke
// point ( second review). The detail rides the result as a non-enumerable property
// point (second review). The detail rides the result as a non-enumerable property
// below, a search device that never serializes.
let unpriceableDetail=null;
if(objective==='lowest_landed_cost')for(const c of packed){
Expand Down
2 changes: 1 addition & 1 deletion test/access-directions.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ test('every legal direction is accepted', () => {
assert.ok(packFallback(request(['-z', '+z', '-y', '+y', '-x', '+x'])).status);
});

// A container that names no doors is the pre- default: the rule is inert, not the
// A container that names no doors is the pre-default: the rule is inert, not the
// container sealed. `[]` is a caller saying "no doors stated" rather than a malformed
// request, so it has to behave exactly like the absent field — otherwise the two spellings
// of one default diverge.
Expand Down
12 changes: 6 additions & 6 deletions test/fallback.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ test('an unpriceable trial cannot win the round on placing more items', () => {
// The snug box holds both bricks but bills 2000 g against a ladder that stops at
// 1500 g; the per-unit box ships one brick at 100. A round key that ranked progress
// first committed the snug box and refused this request, while Rust, Python and PHP
// ship it in two per-unit boxes at 200 ( second review).
// ship it in two per-unit boxes at 200 (second review).
const req = request(
[cube('brick', 100, { weight: '1000 g', quantity: 2 })],
[
Expand Down Expand Up @@ -1294,7 +1294,7 @@ test('the compact lattice path no longer commits to an unpriceable container (qu
// Found by adversarial review: the compact lattice path scored `lowest_landed_cost`
// with the same billed-weight proxy the general path uses, but never stood down for
// it the way it already does for a registered policy rule -- so it could commit to
// one container with nothing to correct that choice once made. ` `'s
// one container with nothing to correct that choice once made. ``'s
// homogeneous-block quality search, unlike the compact path or the default
// `balanced` general search, prices every candidate container exactly rather than by
// proxy, so it is the one shape that already gets this right; this pins that it stays
Expand Down Expand Up @@ -1376,7 +1376,7 @@ test('a portfolio returns the priceable sibling instead of propagating a child r
// The engine used to throw the no-published-price refusal inside the extreme_points
// child run, aborting the request its layer sibling could price at 2400. The refusal
// now fires once, at the outermost frame, on the packing actually selected for
// return -- the choke point Rust, Python and PHP already refuse at ( second
// return -- the choke point Rust, Python and PHP already refuse at (second
// review) -- so the priceable sibling wins on the ordinary score comparison.
const result = packFallback(splitPortfolio(2600));
assert.equal(result.status, 'feasible');
Expand All @@ -1388,7 +1388,7 @@ test('a portfolio returns the priceable sibling instead of propagating a child r

test('alternatives never surface the unpriceable sentinel', () => {
// The losing extreme_points run carries score[1] = MAX_SAFE_INTEGER. The sentinel is
// a search device, never an answer -- alternatives included ( review): the run
// a search device, never an answer -- alternatives included (review): the run
// is filtered out rather than offered as a packing costing 2^53-1 minor units.
const filtered = packFallback(splitPortfolio(2600));
assert.equal(filtered.alternatives.length, 0);
Expand Down Expand Up @@ -1491,7 +1491,7 @@ test('rebalancing refuses an input packing the tariff cannot price', () => {
test('rebalancing applies the same landed-cost admission as packing', () => {
// The current packing uses only `rated`, but `untabled` remains a request option.
// Letting the direct rebalance API ignore it would make its contract weaker than
// packFallback and the native implementation ( second review).
// packFallback and the native implementation (second review).
const base = request(
[cube('parcel', 100, { weight: '500 g' })],
[box('rated', 200, 200, 200, { rate_table: { weight_brackets_g: [2000], prices_minor: [500] } })],
Expand Down Expand Up @@ -1777,7 +1777,7 @@ test('the objective lower bound matches Python on every corpus case', (t) => {
});

test('a sum past the declared ceiling is refused rather than answered', () => {
// , at the same two inputs Python, PHP and Rust assert. The ceiling is declared
//, at the same two inputs Python, PHP and Rust assert. The ceiling is declared
// rather than inherited: this engine's `Number` stops being exact past 2^53, PHP's integers
// silently become doubles, Python's are unbounded and Rust's i128 wraps. If each refused at
// its own limit, a caller would get a number from one engine and a refusal from another for
Expand Down
Loading