WEB / WEB-16.05
Static files, filesystem, and request processing
A URL maps to public assets; the filesystem is a separate namespace and I/O owner. Trace GET, HEAD, and two distinct missing branches.
1. Core · Mechanism
Read every scenario without motion
GET asset
- Choose asset
The client prepared GET /assets/tea.txt?view=plain for a public asset. The HTTP server has not received it; mapping and filesystem reading have not started.
- Duru / Client
- GET /assets/tea.txt?view=plain ready
- HTTP server
- No request
- Public map
- No selection
- Filesystem API
- No I/O
- Request arrived
The HTTP server received method and target; it has not selected a public mapping or started filesystem I/O.
- Duru / Client
- Waiting response
- HTTP server
- GET /assets/tea.txt?view=plain received
- Public map
- No selection
- Filesystem API
- No I/O
- Map selection
The exact whitelist selects the logical pathname; this fixture excludes the query from its key and local work is not a packet.
- Duru / Client
- Waiting response
- HTTP server
- GET /assets/tea.txt?view=plain received
- Public map
- Selected tea.txt
- Filesystem API
- No I/O
- File I/O result
The local fs.readFile for selected tea.txt completed: Çay is four UTF-8 octets, c3876179. Reading in the HEAD branch is this small example’s choice; HTTP does not require identical I/O for every HEAD operation.
- Duru / Client
- Waiting response
- HTTP server
- GET /assets/tea.txt?view=plain received
- Public map
- Selected tea.txt
- Filesystem API
- 4 UTF-8 octets read
- Response policy
The server prepared 200, text/plain; charset=utf-8 and a four-octet body for GET. Content-Length counts bytes; a ready body is not yet at the client.
- Duru / Client
- Waiting response
- HTTP server
- 200; 4 octets ready
- Public map
- Selected tea.txt
- Filesystem API
- 4 UTF-8 octets read
- Response arrived
The client now received 200 and the four UTF-8 octets of the Çay body. Header/body receipt is not browser parsing, DOM or pixel evidence.
- Duru / Client
- 200; Çay; 4 octets
- HTTP server
- 200; 4 octets ready
- Public map
- Selected tea.txt
- Filesystem API
- 4 UTF-8 octets read
HEAD metadata
- Choose asset
The client prepared HEAD /assets/tea.txt for a public asset. The HTTP server has not received it; mapping and filesystem reading have not started.
- Duru / Client
- HEAD /assets/tea.txt ready
- HTTP server
- No request
- Public map
- No selection
- Filesystem API
- No I/O
- Request arrived
The HTTP server received method and target; it has not selected a public mapping or started filesystem I/O.
- Duru / Client
- Waiting response
- HTTP server
- HEAD /assets/tea.txt received
- Public map
- No selection
- Filesystem API
- No I/O
- Map selection
The exact whitelist selects the logical pathname; this fixture excludes the query from its key and local work is not a packet.
- Duru / Client
- Waiting response
- HTTP server
- HEAD /assets/tea.txt received
- Public map
- Selected tea.txt
- Filesystem API
- No I/O
- File I/O result
The local fs.readFile for selected tea.txt completed: Çay is four UTF-8 octets, c3876179. Reading in the HEAD branch is this small example’s choice; HTTP does not require identical I/O for every HEAD operation.
- Duru / Client
- Waiting response
- HTTP server
- HEAD /assets/tea.txt received
- Public map
- Selected tea.txt
- Filesystem API
- 4 UTF-8 octets read
- Response policy
The server prepared 200 and Content-Length: 4 for HEAD but sends no content body. The length refers to the corresponding GET representation; the client has not received the metadata yet.
- Duru / Client
- Waiting response
- HTTP server
- 200; CL 4; no body
- Public map
- Selected tea.txt
- Filesystem API
- 4 UTF-8 octets read
- Response arrived
The client received 200, Content-Length: 4 and zero content octets for HEAD. Empty HEAD content does not establish an empty tea.txt file.
- Duru / Client
- 200; 0 content octets
- HTTP server
- 200; CL 4; no body
- Public map
- Selected tea.txt
- Filesystem API
- 4 UTF-8 octets read
No mapping
- Choose asset
The client prepared GET /assets/missing.txt for a public asset. The HTTP server has not received it; mapping and filesystem reading have not started.
- Duru / Client
- GET /assets/missing.txt ready
- HTTP server
- No request
- Public map
- No selection
- Filesystem API
- No I/O
- Request arrived
The HTTP server received method and target; it has not selected a public mapping or started filesystem I/O.
- Duru / Client
- Waiting response
- HTTP server
- GET /assets/missing.txt received
- Public map
- No selection
- Filesystem API
- No I/O
- Map selection
No exact whitelist entry exists for /assets/missing.txt. Mapping stops here and readAttempts=0 remains. This local check does not examine physical-file existence.
- Duru / Client
- Waiting response
- HTTP server
- GET /assets/missing.txt received
- Public map
- No mapping
- Filesystem API
- No I/O
- Response policy
The server maps the missing entry to a 404 response under this public policy. No filesystem call ran; the prepared response has not reached the client.
- Duru / Client
- Waiting response
- HTTP server
- 404 ready
- Public map
- No mapping
- Filesystem API
- No I/O
- Response arrived
The client now received the 404 response. This status alone cannot distinguish no map entry from ENOENT reading a mapped file; the internal cause requires mapping/I/O records.
- Duru / Client
- 404 received
- HTTP server
- 404 ready
- Public map
- No mapping
- Filesystem API
- No I/O
Missing file
- Choose asset
The client prepared GET /assets/gone.txt for a public asset. The HTTP server has not received it; mapping and filesystem reading have not started.
- Duru / Client
- GET /assets/gone.txt ready
- HTTP server
- No request
- Public map
- No selection
- Filesystem API
- No I/O
- Request arrived
The HTTP server received method and target; it has not selected a public mapping or started filesystem I/O.
- Duru / Client
- Waiting response
- HTTP server
- GET /assets/gone.txt received
- Public map
- No selection
- Filesystem API
- No I/O
- Map selection
The exact whitelist selects the logical pathname; this fixture excludes the query from its key and local work is not a packet.
- Duru / Client
- Waiting response
- HTTP server
- GET /assets/gone.txt received
- Public map
- Selected gone.txt
- Filesystem API
- No I/O
- File I/O result
The local fs.readFile call for mapped fixtureRoot/gone.txt completed with ENOENT. Reading was attempted but no asset bytes were obtained; the client does not know the outcome yet.
- Duru / Client
- Waiting response
- HTTP server
- GET /assets/gone.txt received
- Public map
- Selected gone.txt
- Filesystem API
- ENOENT; own absent file
- Response policy
The server maps this example’s ENOENT outcome to 404. A map entry exists; backing-file reading failed. This choice does not imply that every filesystem error should become 404.
- Duru / Client
- Waiting response
- HTTP server
- 404 ready
- Public map
- Selected gone.txt
- Filesystem API
- ENOENT; own absent file
- Response arrived
The client now received the 404 response. This status alone cannot distinguish no map entry from ENOENT reading a mapped file; the internal cause requires mapping/I/O records.
- Duru / Client
- 404 received
- HTTP server
- 404 ready
- Public map
- Selected gone.txt
- Filesystem API
- ENOENT; own absent file
ACTORS · STATE · DATA FLOW
A URL path is not a filesystem path
Static serving returns selected file bytes as an HTTP representation through a public mapping. The URL /assets/tea.txt maps to fixtureRoot/tea.txt; a physical /assets directory need not exist. The Express static-mount example documents this virtual-prefix distinction. A physical dirname can be absent from the URL, and the process entire filesystem is not automatically a public web area.
Our mapping is an exact whitelist containing tea.txt and intentionally absent gone.txt. Client text is never appended to a filesystem path; a route key selects a fixed map entry. /assets/missing.txt has no mapping and returns 404 without a file read. /assets/gone.txt is mapped but its backing file is unavailable, producing the same outward status. These are namespace selection and I/O availability failures respectively; the external 404 cannot reveal that difference alone.
A file path belongs to the host/container namespace visible to the process. A relative root can depend on its launch directory, so a public root should be explicit and stable. Mapping, OS read permission, and HTTP public policy are different concerns. The OS ability to read a file does not mean it should be served. This example uses only small synthetic files created for itself, with no directory listing or real user files.
Request processing produces bytes and metadata
Processing accepts the method/target, selects the URL pathname, resolves the public map, performs necessary file I/O, and applies response policy. Query view=plain is excluded from this example map key, leaving /assets/tea.txt. A different application may give the query its own contract. As with a repository function, the filesystem read is a local process API here, not an HTTP packet between diagram actors.
Node fs.readFile passes an error or data to its callback; without an encoding, data is a Buffer. The tiny file Çay has UTF-8 octets C3 87 61 79, totaling 4. Three displayed letters are not its Content-Length. text/plain; charset=utf-8 is selected map metadata. A filename extension can inform that policy but alone proves neither the byte format nor permission to serve it publicly.
GET /assets/tea.txt returns four content octets. HEAD can carry metadata for that selected representation; Content-Length: 4 still accompanies no response content, leaving a zero-octet client body. Our HEAD branch reads the file to calculate length; other static servers may use different I/O strategies. Callback success, a prepared response, and client arrival remain separate stages. A later file change does not turn this tiny read snapshot into a guarantee about future state.
2. Red · Trust & Impact
Read every scenario without motion
No mapping
- The public-asset target was selected
Target /assets/missing.txt is a finite artifact case. The public URL is neither a physical directory nor a file path derived from arbitrary client text.
- Public asset target
- /assets/missing.txt
- Map/I/O gate
- Mapping not examined
- Response boundary
- No read outcome
- The exact-map boundary was read
missing.txt has no whitelist entry. With clientTextConcatenatedToFilePath=false, its target path is not freely concatenated into a filesystem candidate.
- Public asset target
- /assets/missing.txt
- Map/I/O gate
- Mapped=false
- Response boundary
- No read outcome
- The I/O-dispatch boundary was separated
Without a mapping, readAttempts=0 remains. Withholding I/O before producing a route body preserves this public-mapping boundary.
- Public asset target
- /assets/missing.txt
- Map/I/O gate
- Read attempts=0
- Response boundary
- No I/O performed
- The failure owner remained correct
Failure is at the mapping boundary; the filesystem was not reached. No mapping does not establish whether a physical disk file exists.
- Public asset target
- /assets/missing.txt
- Map/I/O gate
- Known: no mapped asset
- Response boundary
- File existence not examined
- The public error response was bounded
Status=404 is the selected mapping policy. Internal root/path details or all OS topology are not treated as exposed externally; the other 404 branch has a different cause.
- Public asset target
- /assets/missing.txt
- Map/I/O gate
- Declared status=404
- Response boundary
- No inferred topology disclosure
- Mapping and file authority were not equated
This case shows the unmapped-before-read boundary. Private-asset permission or deployment-root hardening is not inferred from this public-whitelist outcome.
- Public asset target
- /assets/missing.txt
- Map/I/O gate
- Known: mapping/I/O distinction
- Response boundary
- No general filesystem authority claim
File missing
- The public-asset target was selected
Target /assets/gone.txt is a finite artifact case. The public URL is neither a physical directory nor a file path derived from arbitrary client text.
- Public asset target
- /assets/gone.txt
- Map/I/O gate
- Mapping not examined
- Response boundary
- No read outcome
- The exact-map boundary was read
gone.txt has a fixed map entry selecting backing asset fixtureRoot/gone.txt. Mapping does not yet prove that the physical file exists.
- Public asset target
- /assets/gone.txt
- Map/I/O gate
- Mapped=true
- Response boundary
- No read outcome
- The I/O-dispatch boundary was separated
The mapped asset has readAttempts=1. This selected read concerns a known absent fixture file, not directory enumeration or arbitrary filesystem access.
- Public asset target
- /assets/gone.txt
- Map/I/O gate
- Read attempts=1
- Response boundary
- I/O outcome pending
- The failure owner remained correct
ENOENT in own absent fixture file is a backing-file boundary. This case does not recommend the same HTTP mapping for every filesystem error.
- Public asset target
- /assets/gone.txt
- Map/I/O gate
- Known: backing file unavailable
- Response boundary
- No asset bytes available
- The public error response was bounded
Status=404 is the selected mapping policy. Internal root/path details or all OS topology are not treated as exposed externally; the other 404 branch has a different cause.
- Public asset target
- /assets/gone.txt
- Map/I/O gate
- Declared status=404
- Response boundary
- No inferred topology disclosure
- Mapping and file authority were not equated
This case shows a mapped-but-unavailable asset; it neither deletes the map entry nor successfully serves the file publicly.
- Public asset target
- /assets/gone.txt
- Map/I/O gate
- Known: mapping/I/O distinction
- Response boundary
- No general filesystem authority claim
ASSUMPTION · BOUNDARY · CONTROL
Separate the public map boundary from the physical file
For a benign review, connect the documented public asset to the server map entry. The existence of tea.txt alone is not a public-exposure decision; the controlled route, map, and selected response matter together. In designs with multiple static roots, lookup order can choose different assets for one URL. This lesson uses a fixed map without arbitrary paths or directory enumeration.
missing.txt should have readAttempts=0; gone.txt should have one attempt followed by file unavailability. Both can return 404. An internal file error need not expose a complete path in the external response; that mapping policy is a separate choice. Possible problems include an unexpected public root or different bytes for a documented asset. The control is explicit mapping and request-specific read/result association, not inferring filesystem topology from status.
Scope of HEAD and content metadata
An empty HEAD body does not mean an empty file. Content-Length: 4 describes the selected GET representation, while HEAD transfers zero content octets. Receiving Çay through GET also does not prove security controls for the whole processing chain; it connects the whitelist entry, bytes, and selected response contract.
Choosing text/plain metadata from an entry and proving UTF-8 file bytes are different pieces of evidence. Both are tied to the authored public fixture here. Content management, compression, or cache variants may change length/representation in real deployments; none executes here. Preserve the delivery boundary: a completed filesystem callback does not mean the remote client has already received the response.
3. Blue · Secure development & defense
Read every scenario without motion
GET bytes
- The selected-representation record was selected
This branch reviews the GET artifact row. /assets/tea.txt belongs to the public whitelist; the harmless view query remains separate from pathname.
- Asset observation
- GET
- Mapping/byte review
- Representation not examined
- Evidence conclusion
- Delivery fields not read
- Mapping and content source were correlated
The normal row has mapped=true and readAttempts=1. Exact entry, fileContentHex and response fields are tied to the same selected asset.
- Asset observation
- GET
- Mapping/byte review
- Mapped tea.txt; one selected read
- Evidence conclusion
- Delivery fields not read
- The UTF-8 representation calculation was separated
Body Çay has UTF-8 c3876179 with four octets. Character count or filename length does not substitute for content length.
- Asset observation
- GET
- Mapping/byte review
- Çay: c3876179; 4 octets
- Evidence conclusion
- Delivery fields not read
- Declared and received lengths were compared
GET has declaredLength=4 and receivedContentOctets=4. This equality covers selected content bytes, not headers, wrappers or a compression chain.
- Asset observation
- GET
- Mapping/byte review
- Declared=4; received=4
- Evidence conclusion
- Selected content received
- Incorrect causes were not inferred from metadata
Content-Type and filename text alone do not validate encoding or safety of all bytes. This row is limited to the fixed UTF-8 fixture and byte equality.
- Asset observation
- GET
- Mapping/byte review
- Representation metadata scoped
- Evidence conclusion
- No universal file-validation claim
- The asset-evidence conclusion stayed bounded
This artifact correlates mapping, selected I/O and the GET/HEAD response contract. Browser rendering, OS permission hardening and deployment cache/compression variants require separate evidence.
- Asset observation
- GET
- Mapping/byte review
- Known: selected 4-octet representation
- Evidence conclusion
- Other runtime layers unknown
HEAD metadata
- The selected-representation record was selected
This branch reviews the HEAD artifact row. /assets/tea.txt belongs to the public whitelist; the harmless view query remains separate from pathname.
- Asset observation
- HEAD
- Mapping/byte review
- Representation not examined
- Evidence conclusion
- Delivery fields not read
- Mapping and content source were correlated
This fixture supplies mapped=true and readAttempts=1. Reading for HEAD is this small implementation’s choice, not a requirement for identical I/O in every HTTP HEAD request.
- Asset observation
- HEAD
- Mapping/byte review
- Mapped tea.txt; one selected read
- Evidence conclusion
- Delivery fields not read
- The UTF-8 representation calculation was separated
Body Çay has UTF-8 c3876179 with four octets. Character count or filename length does not substitute for content length.
- Asset observation
- HEAD
- Mapping/byte review
- Çay: c3876179; 4 octets
- Evidence conclusion
- Delivery fields not read
- Declared and received lengths were compared
HEAD has declaredLength=4 but receivedContentOctets=0. GET-representation metadata and the absent HEAD content are not forced to share one count.
- Asset observation
- HEAD
- Mapping/byte review
- Declared=4; received=0
- Evidence conclusion
- HEAD has no content
- Incorrect causes were not inferred from metadata
Absence of a HEAD body does not mean the file is empty. Content-Type text/plain; charset=utf-8 and actual byte encoding are also separate checks.
- Asset observation
- HEAD
- Mapping/byte review
- Representation metadata scoped
- Evidence conclusion
- No empty-file inference
- The asset-evidence conclusion stayed bounded
This artifact correlates mapping, selected I/O and the GET/HEAD response contract. Browser rendering, OS permission hardening and deployment cache/compression variants require separate evidence.
- Asset observation
- HEAD
- Mapping/byte review
- Known: selected 4-octet representation
- Evidence conclusion
- Other runtime layers unknown
IMPLEMENTATION · SECURITY CONTROL · VERIFICATION
Read the mapping and I/O ledger together
The normal artifact records target=/assets/tea.txt?view=plain, pathname=/assets/tea.txt, mapping=tea.txt, and fileContentHex=c3876179. These are synthetic relationship observations, not predefined server telemetry fields. Four client octets match the UTF-8 calculation. HEAD has declaredLength=4 but receivedContentOctets=0, which is expected behavior.
An unmapped record with readAttempts=0 stops at map selection. A backing-missing record with one attempt identifies a different I/O failure boundary. This tiny fixture maps expected file absence to 404; not every filesystem error universally means 404. Unexpected internal failures require another server policy. Verify the deployed public root, build asset list, and OS permissions in their own environment, since an external status alone is insufficient.
Do not equate missing observations with a clean result
XPath count(/audit/asset[@mapping="none" and @reads!="0"]) selects authored observations with file reads despite no public mapping. Normal missing.txt gives 0 and a deliberately inconsistent positive fixture gives 1. gone.txt has a mapping, so its single read attempt is benign and outside this condition. With no event, zero still means insufficient evidence.
Assess a correction by connecting map entries, callback results, and response bytes. If a physical root change should retain one logical public asset, verify content continuity separately. The tiny readFile fixture demonstrates Buffer, HEAD, and expected absence handling; it makes no claim about Express static middleware, filesystem permission hardening, browser rendering, or an entire cache/compression chain.
Select the public file boundary explicitly
The static root should contain assets intended for publication, not the entire project. In Express, root selects the physical directory and the mount prefix selects its public URL space; a relative root depends on the process launch directory. Resolve the intended root explicitly and review lookup order when multiple roots exist. This example uses a narrower fixed map: no filesystem read begins without an allowed mapping.
Constrain the public asset list and the runtime’s read permissions together. Keep normal tea.txt content length, HEAD with zero content octets, an unmapped request with zero read attempts, and backing-file absence as separate regressions. Do not turn unexpected I/O failure into a successful empty file or treat every error as 404. Missing map/callback evidence cannot establish a safe file boundary from an external status; this small example does not enforce OS permissions.
NOW APPLY IT TO THE CASE
How do unmapped assets, missing files and HEAD content differ?
The fixed public whitelist does not convert request text into arbitrary file paths. GET and HEAD can share representation metadata while carrying different content.
Read accepted, delivery and committed-effect records at their respective owners. Do not rename unknown caller outcome as business rollback.
Open the related case file ↗READ THE EXAMPLE TOGETHER
Public asset mapping and octet ledger
Select a field and examine what it supports and where the evidence ends.
Read the raw artifact and field explanations
{
"mapping": {
"kind": "exact-public-whitelist",
"entries": {
"/assets/tea.txt": "fixtureRoot/tea.txt",
"/assets/gone.txt": "fixtureRoot/gone.txt"
},
"clientTextConcatenatedToFilePath": false,
"publicPrefixIsPhysicalDirectory": false
},
"normal": {
"method": "GET",
"target": "/assets/tea.txt?view=plain",
"pathname": "/assets/tea.txt",
"mapped": true,
"readAttempts": 1,
"fileContent": "Çay",
"fileContentHex": "c3876179",
"contentType": "text/plain; charset=utf-8",
"declaredLength": 4,
"receivedContentOctets": 4,
"status": 200
},
"head": {
"method": "HEAD",
"mapped": true,
"readAttempts": 1,
"declaredLength": 4,
"receivedContentOctets": 0,
"status": 200
},
"unmapped": {
"target": "/assets/missing.txt",
"mapped": false,
"readAttempts": 0,
"status": 404
},
"backingMissing": {
"target": "/assets/gone.txt",
"mapped": true,
"readAttempts": 1,
"error": "ENOENT in own absent fixture file",
"status": 404
},
"selector": {
"language": "XPath",
"xml": "<audit><asset mapping=\"none\" reads=\"0\"/></audit>",
"xpath": "count(/audit/asset[@mapping=\"none\" and @reads!=\"0\"])",
"expected": 0,
"positiveFixtureXml": "<audit><asset mapping=\"none\" reads=\"1\"/></audit>",
"positiveExpected": 1,
"scope": "Only authored protocol-decision observations, not product log field names or a live HTTP capture.",
"missingFieldBehavior": "Missing observation is insufficient evidence; zero matches is not proof of correct runtime behavior."
}
}- mapping
- Selected mapping from fixed URL keys to fixture paths only.
- declaredLength
- Octets of the GET representation, not transferred HEAD content.
- readAttempts
- Separates unmapped and backing-missing internal causes.
Only two whitelist entries, owned tiny files, and normal HTTP responses; no arbitrary paths, directory listing, or real-server capture.
Two reality checks
A URL containing /assets requires an /assets directory on disk.
A public prefix can be a virtual mount; the server selects its filesystem root separately.
HEAD Content-Length 4 means four body octets arrive.
HEAD sends no content; that header can describe the selected GET representation length.
YOUR TURN
Work through this story.
Predict the outcome, find the evidence boundary, and explain it in your own words.
Does an unmapped /assets/missing.txt request cause a file read?
- Yes; the /assets prefix automatically makes the entire filesystem public.
- No; readAttempts=0 and 404.
Read the explained answer
No; readAttempts=0 and 404. — Without a mapping there is no dispatch to the backing-file owner; client text is not concatenated into a physical path.
Why do the two 404 outcomes carry evidence of different mechanisms?
Selected lesson artifact fields; teaching example
- backingMissing
- {"target":"/assets/gone.txt","mapped":true,"readAttempts":1,"error":"ENOENT in own absent fixture file","status":404}
- unmapped
- {"target":"/assets/missing.txt","mapped":false,"readAttempts":0,"status":404}
- Unmapped performs no read; mapped gone file produces ENOENT during a read attempt.
- 404 always means the file read succeeded but the body is empty.
Read the explained answer
Unmapped performs no read; mapped gone file produces ENOENT during a read attempt. — The public status matches, but a missing mapping and missing backing file have different producer boundaries.
Why are declaredLength=4 and received=0 consistent for HEAD on the tea asset? Is the query/HTTP path a physical file name?
Read the explained answer
HEAD supplies metadata for the selected GET representation but carries no content. Pathname resolves through an explicit whitelist entry; query view=plain is not appended to a physical filename. Çay uses 4 UTF-8 bytes; the public URL prefix is not a filesystem directory and does not automatically grant read/write authorization.
□ I did not count HEAD metadata as an actual body.
□ I separated the HTTP target from physical mapping.
Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples
Sources and scope
- Express — Serving static filesServing static files in Express · root directory and URL distinction · Virtual path prefix · Relative path and process launch directory
- Node.js v24.13.0 — Filesystem APIfs.readFile(path[, options], callback) · readFile callback err/data and default Buffer · Performance Considerations
- Node.js v24.13.0 — HTTP APIhttp.createServer([options][, requestListener]) · response.end([data[, encoding]][, callback]) · response.writableEnded · response.writableFinished
- RFC 9110 — HTTP Semantics3.1 Resources · 3.2 Representations · 8.3 Content-Type · 8.6 Content-Length · 9.2.1 Safe Methods · 9.2.2 Idempotent Methods · 9.3.1 GET · 9.3.2 HEAD · 12.5.1 Accept · 15.5.5 404 Not Found · 15.5.6 405 Method Not Allowed · 15.5.7 406 Not Acceptable